傳送門:
網絡流(一)基礎知識篇
網絡流(二)最大流的增廣路算法
網絡流(三)最大流最小割定理
網絡流(四)dinic算法
網絡流(五)有上下限的最大流
網絡流(六)最小費用最大流問題
轉自:https://blog.csdn.net/water_glass/article/details/6823741
問題模型:
給定一個加權的有向圖,滿足:
(1)容量限制條件:
(2)流量平衡條件:
(2)中的即除了源匯外,所有點都滿足流量平衡條件,則稱G為有源匯網絡;否則
,即不存在源匯,所有點都滿足流量平衡條件,則稱G為無源匯網絡。
將這類問題由易到難一一解決:
問題[1] 求無源匯的網絡有上下界的可行流
由於下界是一條弧上的流必需要滿足的確定值。下面引入必要弧的概念:必要弧是一定流要滿的弧。必要弧的構造,將容量下界的限制分離開了,從而構造了一個沒有下界的網絡G’:
1. 將原弧(u,v)分離出一條必要弧:。(紅色表示)
2. 原弧:。
由於必要弧的有一定要滿的限制,將必要弧“拉”出來集中考慮:
添加附加源x, 附加匯y。想像一條不限上界的(y, x),用必要弧將它們“串”起來,即對於有向必要弧(u, v),添加(u, y),(x, v),容量為必要弧容量。這樣就建立了一個等價的網絡。
一個無源匯網絡的可行流的方案一定是必要弧是滿的。若去掉(y, x)后,附加源x到附加匯y的最大流,能使得x的出弧或者y的入弧都滿,充要於原圖有可行流。
算法:
1. 按上述方法構造新網絡(分離必要弧,附加源匯)
2. 求附加源x到附加匯y的最大流
3. 若x的出弧或y的入弧都滿,則有解,將必要弧合並回原圖;否則,無解。
問題[2] 求有源匯的網絡有上下界的可行流
加入邊(t, s),下界為0(保證不會連上附加源匯x, y),不限上界,將問題[2]轉化為問題[1]來求解。
調用dinic算法
1 bool lowbound_flow(int n, int source, int sink) 2 { 3 init(n + 2); 4 vector<int>tot_in(n + 1), tot_out(n + 1); 5 for(int i = 0; i < (int)u.size(); i++) 6 { 7 if(U[i] < L[i])return false; 8 tot_in[v[i]] += L[i]; 9 tot_out[u[i]] += L[i]; 10 addedge(u[i], v[i], U[i] - L[i]); 11 } 12 addedge(sink, source, 100000000); 13 int super_source = n + 1; 14 int super_sink = n + 2; 15 for(int i = 0; i < n; i++) 16 { 17 addedge(super_source, i, tot_in[i]); 18 addedge(i, super_sink, tot_out[i]); 19 } 20 int ans = Maxflow(super_source, super_sink); 21 //cout<<ans<<endl; 22 for(int i = 0; i < G[super_source].size(); i++) 23 { 24 edge& tmp = e[G[super_source][i]]; 25 if(tmp.f != tmp.c)return false;//判斷是否滿流 不滿流則錯誤 26 } 27 return true; 28 }
問題[3]求有源匯的網絡有上下界的最大流
算法:
1. 先轉化為問題[2]來求解一個可行流。若可行無解,則退出。由於必要弧是分離出來的,所以就可以把必要弧(附加源匯及其臨邊)及其上的流,暫時刪去。再將(T,S)刪去,恢復源匯。
2. 再次,從S到T找增廣軌,求最大流。
3. 最后將暫時刪去的下界信息恢復,合並到當前圖中。輸出解。
這樣既不破壞下界(分離出來)也不超出上界(第2步滿足容量限制),問題解決。
問題[4]求有源匯的網絡有上下界的最小流
算法:
1. 同問題[3]。
2. 從T到S找增廣軌,不斷反着改進。
3. 同問題[3]。
問題[3]與問題[4]的另一種簡易求法:
注意問題[2]中,構造出的(t, s),上下界幾乎沒什么限制。下面看看它的性質:
定理:如果從s到t有一個流量為a的可行流f,那么從t到s連一條弧(t, s),其流量下界b(t, s) = a,則這個圖一定有一個無源匯的可行流:除了弧(t, s)的容量為a外,其余邊的容量與f相同。
證明:如果從s到t的最大流量為amax,那么從t到s連一條下界b(t, s) = a’ > amax的弧(t, s),則從在這個改造后的圖中一定沒有無源匯的可行流:否則將這個可行流中的弧(t, s)除去,就得到了原圖中s到t的流量為a’的流,大於最大流量amax,產生矛盾。
可以二分枚舉這個參數a,即下界b(t, s),每次用問題[1]判斷是否有可行流。這樣就可以求出最大流。
同理,問題[4]要求最小流,只要二分枚舉上界c(t, s)即可。
因為朴素的預流推進算法O(N3),總復雜度為O(N3 log2流量) 。
思路:
無源匯 (附加源匯+最大解決)
有源匯 (附加(T,S)->無源匯)
求有源匯的網絡有上下界的最大流:(s-u v-t之間的路省略了)
(1)對於每條邊,拉出一條必要弧(下限)
(2)去除T到S的邊,然后求S-T的最大流F0
(3)如果S-T的最大流使得所有的S出邊流量滿,T的入邊流量滿,問題有解,否則無解
兩者只要有一者是滿的,另一個一定是滿的,因為總的出流量=總的入流量
有解的時候F0 = 所有下界之和
(4)如果有解,在原來S-T的最大流網絡的基礎上,刪去所有與S和T相連的邊,並且剩下的每條邊的流量都加上下限值,在此基礎上繼續擴充找增廣路,最終的得到的答案就是最大流
挑戰中介紹了第4步另一種方法,直接在S->s連+INF的邊,t->T連+INF的邊,再求一遍S-T的最大流F,那么原圖最大流為F-F0(也就是F-下界之和)