1. 程式人生 > >「學習筆記」網絡流基礎

「學習筆記」網絡流基礎

bzoj3996 特殊 其中 線性 一次 子集 不可 做到 二分

註:此博客寫於 2017.11

前言

今年NOIP2017提高的初賽考到的最小割。這是否意味著網絡流進入NOIP考綱?

蒟蒻Cyani發現,周圍的同學都會網絡流啊。蒟蒻也來學一學姿勢。

比較推薦LRJ的藍書,胡伯濤的論文,關於模版和建模有比較詳細的講解。

聽說CF的網絡流質量挺高的?

還有BZOJ的網絡流。

為了使敘述更加易懂,本文盡可能減少數學符號的使用。

前置技能

最大流

每次找到最短增廣路徑,最壞增廣 \(O(nm)\) 次。所以時間復雜度取決於找最短增廣路徑的時間復雜度。

EK算法。 直接暴力 \(BFS\) ,復雜度 \(O(nm^2)\)

Dinic算法。 按照起點到 \(u\)

的距離分層,沿著分層網絡上的邊增廣,直到 \(s\) 無法到達 \(t\) 。重復以上步驟。最多重復 \(O(n)\) 次,每次復雜度 \(O(nm)\) 。總的復雜度 \(O(n^2m)\)

ISAP算法。 EK算法的改進版,做法類似於Dinic,維護每個點到終點的最大距離(沒有暴力重新計算,而是增廣過程中更新)。需要增加當前弧優化,GAP優化。復雜度 \(O(n^2m)\) ,常數比Dinic小。

推薦ISAP,詳見這篇博文。

網絡流算法Dinic跑二分圖時,復雜度為 \(O(\sqrt n m)\) 。經過實踐,ISAP跑二分圖的復雜度也差不多,似乎常數略大?

最大流最小割定理

一個圖的割定義為, \(s,t\)

分別所屬兩個點集 \(S,T=V-S\) ,代價定義為 \(S\)\(T\) 所有邊的代價總和。

最大流=最小割。

關鍵的證明步驟:是最大流->不存在增廣路徑->可以構造一個割使之等於流->是最大流。證明等價性。

關鍵在於 構造 這個割。

\(S\)\(s\) 能夠達到的點集,那麽對於任意 \(u \in S, v \in T\) 都有 \(f(u,v)=c(u,v)\) ,否則 \((u,v)\) 就屬於殘量了,與前提矛盾。不難發現這個割的容量總和等於流量。

註意:最小割之間的邊一定是滿流的邊,反過來不一定成立。

最小費用最大流

註意到一個網絡的最大流並不是唯一的。有一類題會在邊上附加單位流量費用。最小費用最大流用於解決當流量最大時,最小的費用總和。

EK-SPFA算法。 在EK算法BFS尋找最短路的基礎上,改成SPFA尋找最短路。復雜度 \(O(nmF)\) ,其中 \(F\) 表示最大流量,事實上遠小於這個上界。

zkw費用流。 先挖坑。。

其實我的費用流模版比ISAP短誒。。

常見模型

Simple

這些小技巧的正確性就挺顯然的吧。。

多源多匯。 增加超級源 \(s‘\) ,超級匯 \(t‘\) ,連上流量無窮的邊。

節點容量。 將一個點 \(u\) 拆成兩個點 \(u1,u2\)\(u1\rightarrow u2\) 連上節點容量的邊,入邊連上\(u1\),出邊連上\(u2\)。同樣適用於節點費用。

動態加邊。 不能更改原來邊的容量,費用。註意無後效性!

費用流如何應用? 首先需要確保達到最大流,必要時限流。否則費用流就沒有意義了。

費用不是線性關系。 拆邊。比如流量 \(x\) 的費用為 \(x^2\) ,此時可以分段。具體來說,連上流量 \(1\) ,費用 \(cost(1)-cost(0)\) ,流量 \(1\) ,費用 \(cost(2)-cost(1)\) 。。這個例子對應的流量就是 \(1,3,5,...\)

費用流限流。 在匯點之後再加一條邊到超級匯,限制流量。

最大權閉合子圖

對於一個有向圖 \(G\) 對於其的一個子集 \(N\) 滿足:閉合子圖中的所有節點指向的,都是閉合子圖的節點。賦予每個點一個權值\(wi\),要求最大化閉合子圖的權值。

構圖方法。 對於原圖中的邊,替換為流量無窮的邊;對於權值為正的節點,源\(S\)向這個節點連接容量為\(wi\)的邊;對於權值為負的節點,這個節點連向匯點容量為 \(-wi\) 的邊。

感性證明。 註意到一個性質:新的圖的最小割一定不包含容量無限的邊(稱這種割為簡單個)。於是滿足閉合子圖的定義,每個簡單割的 \(S\) 集一一對應一個閉合子圖。

設所有正數的權之和為 \(sum\) ,最小割為 \(w\) 。發現閉合子圖的權就是 \(sum-w\) ,於是我們需要最小化 \(w\) ,才能最大化閉合子圖的權。

最大密度子圖

對於一個無向圖,定義一個子圖的密度為邊數除以點數。求密度的最大值。

註意到是分數的形式,考慮 分數規劃 ,二分答案 \(g\) 。於是我們要求出 \(|E|-g|V|\) 的最大值,根據與 \(0\)的 關系進一步確定區間。

一種比較容易想到的做法:

註意到,如果我們選擇了一條邊 \((u,v)\) ,那麽一定要選擇 \(u,v\) 。這種依賴關系恰好對應了 最大權閉合子圖 。我們只需要把邊也變成點即可。復雜度為 \(O(\log n \times Maxflow(n+m, n+m))\) 。發現點數過於大。

深入利用特殊性質,得到更好的做法二:

因為要應用最小割,所以首先轉成最小化的形式:\(g|V‘|-|E‘|=\sum _{v \in V‘} g - \sum_ {e \in E‘} 1\)。前面部分無需改變,考慮如何將後面部分與最小割聯系。

註意到後面部分就是 \(\frac 1 2 \times \sum _ {v \in V‘} d[v] - c[V‘, V-V‘]\),左邊部分與之前的合並在一起,右邊部分就是 \(V‘,V-V‘\) 之間最小割。附加所有節點到\(T\)的邊容量為 \(g - \frac {d[v]} 2\)註意,容量有可能為負數,需要增加一個足夠大的固定值。 最終,流網絡的點數為\(n\)

這個模型很容易推廣到帶邊權與點權的問題。

二分圖點權最大獨立集&覆蓋集。

話說在無向圖裏,這個問題是NPC的呢。但是二分圖就可用最大流跑啦。

覆蓋集:\(U \in V\)\(\forall (u,v) \in E, u \in U \vee v \in U\)

獨立集:\(U \in V\), \(\forall (u,v) \in E, u \notin U \vee v \notin U\)

發現最小覆蓋集和最大獨立集互補。只用考慮最小覆蓋集。 根據定義很顯然啊。

考慮這樣建邊,新建 \(S\) ,對每個 \(X\) 部的點 \(i\) 連上容量為 \(a[i]\) 的邊,邊 \((i,j)\) 就要從 \(i\)\(j\)\(\infty\) 的邊,每個 \(Y\) 部的點 \(j\)\(T\) 連容量為 \(b[j]\) 的邊。

註意到最小割的性質。路徑 \(S \rightarrow u \rightarrow v \rightarrow T\) ,至少有一條邊被割,不可能是 \(u \rightarrow v\) ,對應到原問題就是 \(u,v\) 中至少選擇一個。

所有點權之和減去最小覆蓋集就是最大獨立集合辣。

應用,論文題:BZOJ1324 Exca王者之劍

一個一般化,基於二元關系的建模方法

適用問題:\(N\) 個元素,每個元素可以選或者不選,有對應的代價。描述若幹個二元組,不同關系是產生不同的代價。求中代價的最小/最大值。

找出題目中的二元關系。 有必要時需要附加點。如果出現類似與 \(x\) 選了, \(y\) 必須選的情況,相當於 \(y\) 沒選但 \(x\) 選了的代價為 \(\infty\)

具體方法。 新建一個源點 \(S\) 和匯點 \(T\) ,割 \((S,u)\) 表示不選,割 \((u,T)\) 表示選。對於所有二元關系 \((u,v)\) ,在 \((u,v),(v,u)\) 連上容量為 \(e,f\) 的邊。根據四種情況可以列方程,解出所有容量,跑最大流即可。

可能出現的情況以及應對方法。解方程後得到中間兩條邊的容量之和\(K\)為負數,如果圖不是二分圖,就GG。否則考慮令\(Y\)部的點,與\(S,T\)相連的邊的意義交換。可以使中間的容量之和變為\(-K\)

最大權閉合子圖,最大密度子圖也是這種二元關系建模的特殊應用。

具體參見 彭天翼《淺析一類最小割問題》

容量上下界的可行流

未完待續。

一些好題

BZOJ1305 [CQOI2009]dance跳舞\(n\) 個男生, \(n\) 個女生。有一個 \(n \times n\) 的關系,表示是否願意一起跳交際舞。每個人最多和 \(K\) 個不喜歡的異性跳舞。每個人不會和一個人跳多次舞。每一輪所有人都要一起跳舞。問最多能進行幾輪。

二分+最大流二分圖匹配。 顯然需要二分答案\(ans\)。考慮將每個點拆分為兩個,喜歡\(u1\),不喜歡\(u2\)。考慮\(S\)連向\(u1\)容量\(ans\)\(u1\)連向\(u2\)容量\(K\)。最後,再是喜歡的點對連接,不喜歡的點對連接,容量都為\(1\)。跑最大流,如果\(S\)到所有\(u1\)都是滿流的,就可行。

BZOJ3630 [JLOI2014]鏡面通道 有兩塊鏡面 \((0,0) \rightarrow (X,0)\)\((0,Y) \rightarrow (X,Y)\) 。中間有若幹個正方形和圓形鏡面。問最少拿走幾塊圖形,使得左面的光能夠通過反射照到最右面。

計算集合+節點容量+最小割。 水能過去,光就能過去。很顯然的一個結論吧。。隨便感受下就好了。

於是我們需要刪除最少的圖形,使得左右連通。也即一個割。考慮拆點,建立節點容量,為 \(1\) 。在兩連通的兩個圖形之間,要建容量為無窮的邊。下鏡面作為 \(S\) ,上鏡面作為 \(T\) 。跑最大流即可。

BZOJ1565 [NOI2009]植物大戰僵屍 有一個 \(n \times m\) 的矩陣,每個位置有一個植物,每個植物會保護若幹個位置。僵屍只能從每一行的最右端開始進攻,而且不能進入被保護的位置。每攻擊一個植物,可以獲得一個價值(可能為負數),求最後能夠獲得多少的價值。

拓撲排序,最大權閉合子圖。 發現僵屍只能從每一行的最右端開始進攻其實也是一種保護關系,每個植物保護它左邊的植物。考慮拓撲排序,對於構成環的節點,我們就刪去。對於剩下的DAG,運用經典的最大權閉合子圖模型即可。

BZOJ3996 [TJOI2015]線性代數 給出一個 \(n \times n\) 的矩陣 \(B\) 和一個 \(1 \times N\) 的矩陣 \(C\) 。求一個 \(1 \times N\)\(01\) 矩陣 \(A\) .使得 \(D =(A \times B-C) \times A ^ T\) 最大。其中 \(A^T\)\(A\) 的轉置。輸出 \(D\)\(n \leq 100\)

最大權閉合子圖。 一看到題的時候,一臉懵逼。。這個數學題可以用網絡流??

其實還是很水的啦。註意到,\(Ans = \sum _{i = 1} ^ {n} \sum_ {j=1} ^{n} A[i] \times A[j] \times B[i][j] - \sum _ {i=1} ^{n} A[i] \times C[i]\)

如果選擇了 \(B[i][j]\) 那麽一定要選擇 \(A[i],A[j]\) ,就是一個最大權閉合子圖啦。

算復雜度,點數 \(|V|=O(n^2)\) ,邊數 \(|E|=O(n^2)\) 。所以最大流的復雜度是 \(O(n^6)\) ??!!

WTF,復雜度直接爆炸啊!確定自己沒有看錯??

吶,這個圖是二分圖誒。。所以復雜度就是 \(O(n^3)\) 啦。。

BZOJ2127 happiness 有一個\(n \times m\)的班級,每個學生會選擇文科或者理科,得到不同的喜悅值。如果一個人與前後左右選擇的科目相同,可以獲得額外的喜悅值。問喜悅值最大為多少。\(n,m \leq 100\)

根據二元關系建圖。

做完這道最小割,我整個人都最小割了。。----hzwer

應為要使答案最大化,我們一開始先將喜悅值取負。

加上 \(u,v\) 都選文科的喜悅值為 \(-v1\) ,都選理科的喜悅值為 \(-v2\) ,其他情況下喜悅值為 \(0\) 。可以發現 \((u,v)\) 需要連 \(v1+v2\) 的無向邊, \((S,u),(S,v)\)\(v2\) 的無向邊, \((u,T),(v,T)\)\(v1\) 的無向邊。已經取正數最後減去 \(v1+v2\) ,再除以 \(2\) 即可。

對於每個人自己選擇文理科,另外處理。使用同樣的技巧,首先把邊取負,再加上 \(a[u]+b[u]\) 。最後一起求最小割,減去多余的,取負即可。

BZOJ1834 [ZJOI2010]network網絡擴容 給定一個有向圖,每條邊的容量和費用。每增加一單位容量就會增加一單位費用,求最大流增加\(K\)的最小費用。

很顯然的一個費用流建模。考慮首先按照給定的圖構造,每條邊附加一條容量無限,費用為 $Wi $的邊。跑費用流。

如何保證最大流恰好增大到 \(K\) ?求出原來的最大流,附加一個超級匯,限制流量即可。

BZOJ2597 [WC2007]剪刀石頭布 給定一個競賽圖,有些邊的方向還未確定。定向這些邊,使得三元環的個數最多,輸出方案。 \(n \leq 100\)

容斥原理,分段費用。 發現正著做很難,考慮 補集轉換 。註意到, 一個不滿足條件的三元組 \((a,b,c)\) 對應於 \(a,b,c\) 之一的兩條出邊。

\[ANS = \binom {n} {3} - \sum _ {i = 1} ^ {n} \binom {out[i]} {2}\]

考慮為這些邊建立點 \(e[1], e[2], e[3], ...\) 。每個 \(e[i]\)\(T\) 連上容量 \(1\) 費用 \(0\) 的邊(容量為 \(1\) 限制它只能作為條邊的出邊)。

對於邊 \((u, v)\) ,如果這條邊能夠成為 \(u\) 或者 \(v\) 的出邊,就連上 容量 \(1\) 費用 \(0\) 的邊。

每個點 \(u\) 的流量需要 \(S\) 來提供,根據分段費用的方法,建立 \(n-1\) 條容量為 \(1\) 費用依次為 \(0, 1, 2, 3, ..., n-2\)的邊。

跑費用流。考慮復雜度,點數 \(O(n^2)\), 邊數 \(O(n^2)\), 至多增廣 \(O(n^2)\) 次,總的復雜度 \(O(n^6)\)。實際上,由於圖較為稀疏,所以使用SPFA的費用流達不到這個上界。

LRJ的模版好慢啊啊啊,卡了半天常數。。。有時間學學ZKW費用流QAQ

BZOJ3171 [TJOI2013]循環格 有一個 \(n \times m\) 的矩陣,每個元素表示了一個方向(上下左右)。問最少改變多少元素的方向,使得從任意位置出發,按照元素的方向運動,最後能到達原來的位置。 \(n \leq 15\)

環的性質,費用流建模。 考慮環的性質: 所有節點的出度和入度都為 \(1\) 考慮拆點,\((x,y,1),(x,y,2)\)\(S\) 連向每個 \((x,y,1)\) 容量為 \(1\) 費用為 \(0\) 的邊。 \((x,y,1)\) 向四周的 \((x‘,y‘,2)\) 連上容量為 \(1\) 費用為 \(1\) (當與原來方向相同時為 \(0\) )的邊。所有 \((x,y,2)\) 連向 \(T\) 容量為 \(1\) 費用為 \(0\) 的邊。跑最小費用最大流。

註意到,費用最小的前提的是 流量最大,所以與 \(S,T\) 相連的邊一定是滿流的(很顯然一定能做到)。 這樣就能夠限制每個位置的出度入度都為 \(1\)

BZOJ2879 [NOI2012]美食節。\(n\) 種菜和 \(m\) 個廚師,廚師 \(j\) 燒菜 \(i\) 所需的時間是 \(t[i][j]\) ,一個廚師一次只能燒一樣菜。現在知道有 \(p[i]\) 個學生需要第 \(i\) 道菜。求所有學生所需要的等待時間總和的最小值。 \(n \leq 40, m \leq 100, \sum p[i] \leq 800\)

神奇的費用流建模,動態加邊。 顯然需要劃分為兩部分點。

一開始的錯誤想法:建立 \(n\) 個點 \(a[1], a[2], a[3], ...\)\(S\) 連向這些點容量 \(p[i]\) 費用 \(0\) 的邊。為廚師建立點 \(b[1], b[2], b[3], ..., b[m]\) 連向 \(T\) 容量為 \(1\) 費用為 \(0\) 的邊。所有 \(a[i], b[j]\) 連接 容量無限, 費用 \(t[i][j]\) 的邊。每一次增廣後,我們得到了 \(S \rightarrow a \rightarrow b \rightarrow T\) 的路徑。相當於廚師選擇燒這樣菜。然後我們再連接 \(b[j]\)\(T\) 的邊,容量仍然為 \(1\) , 費用要增加先前的時間。

吶,看上去沒錯啊?怎麽會比答案少呢??事實上就是因為費用流算法存在反向邊,目的是 退流 。所以一定程度上網絡流也是貪心??然後退流就是經典的 反悔操作 。這就使得這個算法中存在後效性(退流之後,新的邊就不合法了)。

考慮一種新的權值計算方式。 假設一個廚師燒菜時間的序列: \(t1, t2, t3, ..., tn\) 那麽總共的時間為 \(n \times t1, (n-1) \times t2, ..., tn\) 。考慮倒著計算,依次加入 \(k \times t\) 的邊。

拆點!為了使 \(1\) 倍時間, \(2\) 倍時間,等,都只計算一次。考慮將每個廚師拆成 \(\sum p[i]\) 個點,依次表示燒倒數第 \(k\) 條邊。然而這麽多邊建出來會T啊。考慮動態建邊,當一次增廣,燒完倒數第 \(k\) 道菜,加入倒數第 \(k+1\) 道菜。

計算一下復雜度。需要增廣 \(O(\sum p[i])\) 次,點數始終保持 \(O(n+m)\) 個, 邊數始終保持 \(O(nm)\) 條,於是總的復雜度為 \(O((n+m)nm \times \sum p[i])\)SPFA-EK費用流卡著時限過QAQ。看來要學ZKW費用流了QAQ。

BZOJ1001-[BeiJing2006]狼抓兔子。 給定一個平面圖,求最小割。

平面圖轉對偶圖。 此題暴力ISAP可過。不過經典的做法是,求出他的對偶圖(區域變成新的點,相鄰連邊)。於是跑最短路就好了。

BZOJ2400-Optimal Marks。 給定一個無向圖,某些點的權值已經知道,請確定剩下點的權值。定義一個圖的代價為所有邊兩端點權的異或值之和。求無向圖的最小代價,當代價最小時,最小的點和。

按位拆分,最小割。 顯然可以按位拆分。顯然可以最小割。S集的權為0T集的權為1。如果是已經確定的位,就與S or T連上流量為INF的邊。原圖連流量為1的邊。

比較不顯然的是最小點權和。最小費用最大流?TLE!

這裏有一個Trick。我們把所有的流量1改為1000。對於所有與S沒有直接連邊的點,連上流量為1的邊。當割最小時,先要滿足價值最小,其次滿足點權和。

BZOJ1280-Emmy賣豬pigs。 有若幹個豬圈,豬圈裏養了若幹頭豬。依次來了幾位客人,每位客人帶上了若幹個豬圈的鑰匙,他最多可以買 \(ai\) 頭豬。之後,你可以把這些豬圈中的豬任意安排,再關上。問最多能賣多少豬?

經典最大流建圖。 不難發現一個性質:當一個豬圈中已經有一個客人來過後,第二位客人能夠買前一位客人能賣的豬。於是建圖就很simple了:

每個豬圈(源點)向到這個豬圈的第一位客人連流量為豬的數量的邊,每個客人向後續有重疊的客人連流量為無窮的邊。每位客人向匯點連容量為 \(ai\) 的邊。

BZOJ1449-[JSOI2009]球隊收益\(n\) 支球隊,每支球隊已經贏了 \(win[i]\) 場,輸了 \(lose[i]\) 場,每支球隊還有參數 \(c[i],d[i]\) 。剩下的球隊會進行 \(m\) 場比賽。問所有球隊的價值總和的最小值。一個球隊的價值定義為 \(c[i] \times win‘[i] + d[i] \times lose‘[i]\) (代表最終的勝利,失敗的場數)。

拆邊費用流。 發現一場比賽對應兩個價值,但是流量無法憑空產生,那麽該如何建圖呢?

有一個很秒的想法,註意到每只隊伍最終勝利和失敗的次數的總和是比邊的。首先假設剩下的場數都是輸的,然艘計算每多勝一場可以增加的權值。由因為這個增量是顯然遞增的,所以是正確的。

BZOJ3280-小R的煩惱 你需要一些xx,第 \(i\) 個商店有 \(li\) 個xx,每個xx要 \(pi\) 的代價。你在第 \(i\) 需要 \(ai\) 個xx。每個xx在用完一天之後會XX,所以,拿去修理它,第 \(i\) 個地方,需要修理 \(d\) 天,需要 \(qi\) 的花費。求最小需要花的前。

奇妙的費用流。 註意到,一個xx可以有多次貢獻,對應到流裏面,流量並不會增加,這樣應該如何建圖?註意到,每天結束後有固定 \(ai\) 個死掉的xx,這個流量可以由原點提供,於是我們就得到建圖方式辣。註意到要考慮:每天多出來死的;活的到匯點;第一天新來活的;每天把死的修d天變成活的;前一天活的不用,到後一天;前一天死的不修,到後一天。。貌似這樣不太好QAQ,大概就這這樣理解啦。 建圖如下表:

起點 終點 流量 費用
0 dead[i] a[i] 0
live[i] 2*n+1 a[i] 0
0 live[1] l[j] p[j]
dead[i] live[i+d[j]] q[j]
live[i] live[i+1] 0
dead[i] dead[i+1] 0

BZOJ5120-[2017國家集訓隊測試]無限之環\(n \times m\) 的方格,每個方格的上下左右,有可能存在接口,也有可能沒有。可以順時針或逆時針旋轉。問最少操作幾次,使得每個接口總有一個接口與之連通。很顯然,總共存在15種方塊(不算空的)。

二分圖,費用流。 註意到 網格圖是一個二分圖 所以考慮黑白染色,就變成了兩部分的連接。很顯然拆成四個方向的四個點,首先對應接觸的點先連接,考慮源點流向X集。

由於每部分的流量總量不變。所以考慮S流向默認的接口 \((1,0)\) 的邊。而旋轉就是接口之間,花費一定的費用來轉移流量。

以只有一個接頭為例。首先S連向那個接頭 \((1,0)\) 的邊,然後那個接頭連向兩邊 \((1,1)\),向對面連 \((1,2)\) 的邊。

相鄰的兩個接頭也類似,三個接頭的與一個接頭的恰好相反。

註意空方塊和四個接頭的沒有必要旋轉。

註意那個對面的兩個接頭的不能旋轉。。因為出題人也建不出圖。。hhh。。

這個建圖嘛,我手擼了1h。共6k,竟然1A了。哈哈哈。

「學習筆記」網絡流基礎