1. 程式人生 > 其它 >[題目小結] 網路流

[題目小結] 網路流

東拼拼,西湊湊,不就又水出一篇部落格嗎

例 1. \(\text{UVA12125 March of the Penguins}\)

首先可以想到在 \([1,n]\) 列舉匯點,檢驗最大流是否為企鵝總數。

每個點初始的企鵝數可以由 \(S\rightarrow i\) 的邊表示,那跳出的企鵝呢?因為跳到哪個冰塊是未知的,所以不妨將 \(i\) 拆成兩個點 —— 在入點與出點之間連邊權為跳出企鵝數的邊。

例 2. \(\text{UVA11082 Matrix Decompressing}\)

這個建圖真的好妙啊!假設每一行、列的數字和分別為 \(r_i,c_i\),將行、列抽象成點,構造邊 \(\langle S,i,r_i-m \rangle\)

\(\langle i,T,c_i-n \rangle\)。最後將任意行與列之間連線容量為 \(19\) 的邊。

之所以將權值減一是因為網路流跑出的容量包含零,將區間變成 \([0,19]\),再加一就可以復原。最後如果最大流滿流就是有解的。

例 3. 圈地計劃

不在同一部分是不好判斷的,我們將網格圖黑白染色,將黑格的商業區看作白格的工業區,這樣就轉化成了同一部分的問題!

對於兩個相鄰的點,連權值為 \(c_{i,j}+c_{i+1,j}\)雙向邊\(\text{sum}\) 只增加 \(c_{i,j}+c_{i+1,j}\)。這是因為這條雙向邊不可能同時刪除所有方向。程式碼:\(\rm Link.\)

另外還有一種複雜度較高的做法:黑白染色之後,對每兩個相鄰的點建兩個虛點 \(g_1,g_2\),表示同時在左部/右部,分別連 \(\langle S,g_1 \rangle\)\(\langle g_2,T\rangle\),再以 \(\text{infty}\) 的權值連線虛點和相鄰點。因為枚舉了在哪一部,所以複雜度提高。

例 4. 「雅禮集訓 2017 Day8」價

先說一下建圖:

  • 從源點向藥 \(i\) 連線權值為 \(\text{infty}-w_i\) 的邊。
  • 從藥向對應的藥材連權值為 \(\text{infty}\) 的邊。
  • 從藥材向匯點連權值為 \(\text{infty}\)
    的邊。

跑一遍最小割,答案就是最小割減去源點連出邊的權值。

要想理解這個模型,首先得明確幾個性質:

  • 最小割不可能割去藥與藥材之間的邊。因為一種藥至少對應一種藥材,所以割這條邊一定不如割掉藥材與匯點連邊優。
  • 割掉源點與藥的連邊相當於不選此藥;割掉匯點與藥材的連邊相當於選擇此藥材。第一個比較好理解,對於第二個,考慮求最小割的過程:若藥邊未割(即選擇藥),那麼藥材必須割;若割,則藥材可以不割。
  • 一定只會割 \(n\) 條邊。所有邊都帶 \(\text{infty}\),多選一條邊一定不優。
  • 藥和藥材數相等。考慮上一條,即 —— 不選的藥與選擇的藥材之和為 \(n\),而不選的藥與選擇的藥之和也為 \(n\)!所以結論得證。

最後考慮一下為什麼定義 "割掉源點與藥的連邊相當於不選此藥" 這樣鬼畜的狀態。如果我們將源點與藥的連邊權值改成 \(\text{infty}+w_i\),即 "割掉源點與藥的連邊相當於選擇此藥",此時藥材邊可以不割,但實際上我們需要必須不割!

總結:網路流建圖時可以設計狀態描述 "必須" 與 "可以"。

例 5. \(\text{UVA10735 Euler Circuit}\)

由於有向圖存在歐拉回路當且僅當圖連通且所有點的入度等於出度。考慮先將無向邊定向,然後分配度數。

\(d'_i=\) 出度 \(-\) 入度,那麼若 \(d'_i\) 為奇數則無解,否則令 \(d_i=d'_i/2\)。對於無向邊 \(\langle u,v \rangle\),若給它定向 \(u\rightarrow v\),就在網路中連一條 \(u\rightarrow v\),容量為 \(1\) 的邊,表示 \(u\) 可以貢獻一個 "度" 給 \(v\)

對於 \(d_i>0\) 的點,從源點連容量為 \(d_i\) 的邊;反之,向匯點連 \(-d_i\) 的邊。這樣最後檢驗從源點流出的邊是否滿流即可(檢驗匯點也可)。

跑一遍網路流後,當一條邊的殘餘容量為零時,就說明反向。輸出的時候記得將邊反向遍歷,就像這樣:

void Print(int u) {
    while(!E[u].empty()) {
        int v=E[u].back(); E[u].pop_back();
        Print(v); printf(" %d",u);  
    }
}

例 6. \(\text{[JSOI 2009]}\) 遊戲

首先一個比較經典的轉化是按座標之和的奇偶性將格點分成兩部,這樣 \(\text{Alice}\)\(\text{Bob}\) 就只能分別走某一部。

可以證明,當 \(\text{Alice}\) 從一個 不一定 屬於最大匹配的點出發,\(\text{Alice}\) 有必勝策略 —— 先假設這個點不屬於某個最大匹配 \(G\),此時 \(\text{Bob}\) 一定 只能 走到一個屬於 \(G\) 的點,現在 \(\text{Alice}\) 可以選擇走到與當前點匹配的點,下一步,\(\text{Bob}\) 可以走哪些點呢?

看似可以走不屬於 \(G\) 的點,但事實上,如果存在這種點,我們就成功找到了一條增廣路!這並不符合 \(G\) 是最大匹配的條件。於是 \(\text{Bob}\) 只能走屬於 \(G\) 的點,\(\text{Alice}\) 沿用之前的策略,就可以達到必勝的效果。

於是問題轉化為,如何求得不一定屬於最大匹配的點。最 \(\text{naive}\) 的思路是刪去一個點再求最大匹配,不過難道就沒有更高效的做法嗎?

事實上,先用 \(\text{Dinic}\) 求出一個最大匹配,從一個非匹配點出發,如果到達與自己 同部 的點,那麼這些點都是非匹配點。這實際上是 "非匹配 - 匹配 - 非匹配 ..." 的過程,將匹配反向就可以使同部的點狀態取反。

具體實現:

  • 從源點出發沿 未滿流 的邊走,回到 \(S\) 部。
  • 從匯點出發沿 滿流 的邊走,回到 \(T\) 部。

注意特判走到源/匯的情況。

例 7. \(\text{[SDOI 2016] }\)數字配對

考慮網路流。思考如何判斷數字配對的條件 —— 樸素顯然是 \(\mathcal O(n^2\sqrt V)\) 的,難以接受。

試圖將質因數分解從二層迴圈拋到外面去:其實可以發現,配對條件滿足當且僅當存在整除關係且質因數個數和相差為 \(1\)。這個問題就解決了。

如何連邊?通過上文不難發現這是一張二分圖,按質因數個數的奇偶性分類。於是要求最大化配對就變成了最大流。由於需要保證獲得的價值總和不小於 \(0\),我們優先選擇費用更大的,也即 "最大費用最大流"。這個可以用 \(\text{spfa}\) 來解決。