最大流 Ford-Fulkerson 算法
Ford-Fulkerson 算法
基本思想是從任何一個可行流開始,沿增廣路徑對流進行增廣,然后不斷重復此過程,直到網絡中不存在增廣路徑為止。
0.流網絡G=(V,E)上的一個流的三個條件
- 容量約束: f(u,v)≤c(u,v) 對?uv∈E成立
- 反對稱性: f(u,v) = - f(v,u)
- 守恒約束: Σu∈VΣ_{u∈V}Σu∈V? f(u,v)f(u,v)f(u,v)對任意u∈u∈u∈VVV-{s,ts,ts,t}成立
1.剩余網絡(余圖)
簡單來說就是網絡的總可承載流量-現有的流量,所得到的剩余網絡。
給定圖GGG中的流fff
余圖 GfG_fGf?
同樣的結點,中間結點和s,t
求余圖的流程:
- 對于每條邊 eee 滿足 cec_ece? > f(e)f(e)f(e) 賦給權重 cec_ece? - f(e)f(e)f(e) (剩余容量)
- 對于每條邊 e=(u,v)e = (u,v)e=(u,v) 給其逆向邊(v,u)(v,u)(v,u)賦給權重f(e)f(e)f(e) (剩余容量,如果f(e)=0f(e)=0f(e)=0便不賦予)
通俗來講,就是先把這條邊按邊的容量方向取反,如果這條邊之前存在流量并且沒有用完的話,就用總容量-已用流量作為這條邊的補,加入剩余網絡中。
比如
如下圖所示:
以中間那個為例(u到v),u到v的容量是30,實際上只用了20,那么從u到v的管道還剩10,所以剩余網絡中就有一條從u到v值為10的邊,反向(從v到u)的20是用管道的總容量30減去從u到v的管道10得到的
案例2:剩余網絡
2.增廣路徑
給定一個網絡G,令fff為圖GGG的一個流,則稱剩余網絡GfG_fGf?,中從sss到ttt的一條有向路徑ppp為增廣路徑。
就是在剩余網絡中從源點到匯點找一條路徑
給定圖GGG中的流fff,對應的余圖 GfG_fGf?
基于之前的余圖,找到新的流,如下圖所示,為了更好的區分,再放一張之前的余圖
對剛才的剩余網絡,我們尋找紅色標記的一條增廣路徑如圖所示:
如果我們利用增廣路徑進行擴展的話,顯然還是滿足容量約束條件的
Ford-Fulkerson 算法思想
從任何一個可行流開始,沿增廣路徑對流進行增廣,然后不斷重復此過程,直到網絡中不存在增廣路徑為止。
其偽代碼如下:
對于所有e初始化 f(e) = 0While 余圖中存在s-t 路徑 P:沿著路徑P增廣 f 得到新的 f‘ 和新的余圖 沿著P增廣 f :找到路徑的最小容量沿著路徑修改權重3.網絡的割
給定一個網絡G=(V,E)G=(V,E)G=(V,E) ,網絡中的一個割(S,T)(S,T)(S,T)是把網絡G的頂點集V分成兩個子集SSS和T=V?ST=V-ST=V?S且s ∈\in∈ S , t ∈\in∈T (一個包含源點,一個包含匯點),
其中流過割(S,T)(S,T)(S,T)的容量記為c(S,T)c(S,T)c(S,T),定義為割(S,T)(S,T)(S,T)中流過分界線的容量之和
流過割(S,T)(S,T)(S,T)的流量記為fff(S,T)(S,T)(S,T) ,定義為割(S,T)(S,T)(S,T)中流過分界線的現有流量之和。
例如:
有推論:
網絡G中任意流f的值被G的任意割的容量所限制,即∣f∣≤c(S,T)|f|≤ c(S, T)∣f∣≤c(S,T)
4.最大流最小割定理
增廣路定理:網絡達到最大流當且僅當剩余網絡中沒有增廣路徑,這也是 Ford-Fulkerson 算法的基礎
最小割等于最大流
給定一個網絡G=(V,E)G = (V,E)G=(V,E) ,令 f 為 G 的流,則下列三個
結論相互等價:
是指在一個網絡流中,能夠從源點到達匯點的最大流量等于如果從網絡中移除就能夠導致網絡流中斷的邊的集合的最小容量和。即在任何網絡中,最大流的值等于最小割的容量。
形象地理解一下:
好比你家是匯 自來水廠(有需要的同學可以把自來水廠當成銀行之類 以下類似)是源
然后自來水廠和你家之間修了很多條水管子接在一起 水管子規格不一 有的容量大 有的容量小
然后問自來水廠開閘放水 你家收到水的最大流量是多少
如果自來水廠停水了 你家那的流量就是0 當然不是最大的流量
但是你給自來水廠交了100w美金 自來水廠拼命水管里通水 但是你家的流量也就那么多不變了 這時就達到了最大流
割集好比是一個恐怖分子, 把你家和自來水廠之間的水管網絡砍斷了一些 然后自來水廠無論怎么放水 水都只能從水管斷口嘩嘩流走了 你家就停水了
割的大小應該是恐怖分子應該關心的事 畢竟細管子好割一些 而最小割花的力氣最小
具體的證明分三部分
1.任意一個流都小于等于任意一個割
這個很好理解 自來水公司隨便給你家通點水 構成一個流
恐怖分子隨便砍幾刀 砍出一個割
由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量
每一根被砍的水管的水本來都要到你家的 現在流到外面 加起來得到的流量還是等于原來的流
管子的容量加起來就是割 所以流小于等于割
由于上面的流和割都是任意構造的 所以任意一個流小于任意一個割
2.構造出一個流等于一個割
當達到最大流時 根據增廣路定理
剩余網絡中s到t已經沒有通路了 否則還能繼續增廣
我們把s能到的的點集設為S 不能到的點集為T
構造出一個割集C[S,T]C[S,T]C[S,T] S到T的邊必然滿流 否則就能繼續增廣
這些滿流邊的流量和就是當前的流即最大流
把這些滿流邊作為割 就構造出了一個和最大流相等的割
3.最大流等于最小割
設相等的流和割分別為FmF_mFm?和CmC_mCm?
則因為任意一個流小于等于任意一個割
任意FFF≤FmF_mFm?=CmC_mCm?≤任意CCC
定理說明完成
引用:[Poj 1459網絡流(一) {基本概念與算法}
##偽代碼:
FordFulkerson(G, s, t, c) //初始化for 每一條路徑 (u,v) ∈E dof (u,v) ←0 //初始化f(e)=0Gf ←G //初始化剩余網絡 //查找增廣路徑while Gf中存在一條增廣路徑 p docf(p)=min{cf(u,v)| uv是p上的邊} //cf(p) 作為 p 路徑上的最小容量(瓶頸容量)for each edge (u,v) in p dof (u,v) ← f (u,v)+ cf(p) //講選擇的增廣路徑加入圖中,更新邊的流量最后還需要更新剩余網絡Gf案例:對于網絡:
計算剩余網絡:
選擇增廣路徑
然后增加對應的流量即可
之后循環往復,直到找不到新的增廣路徑即可
1.最多要增廣多少次?
可以證明 最多O(VE)次增廣 可以達到最大流 證明略
2.如何找到一條增廣路?
先明確什么是增廣路 增廣路是這樣一條從s到t的路徑 路徑上每條邊殘留容量都為正
把殘留容量為正的邊設為可行的邊 那么我們就可以用簡單的BFS得到邊數最少的增廣路
3.如何增廣?
BFS得到增廣路之后 這條增廣路能夠增廣的流值 是路徑上最小殘留容量邊決定的
把這個最小殘留容量MinCap值加到最大流值Flow上 同時路徑上每條邊的殘留容量值減去MinCap
最后 路徑上每條邊的反向邊殘留容量值要加上MinCap
顯然算法的運行時間取決于增廣路徑 p該如何確定,使用BFS或DFS查找增廣路徑的時間為O(V+E’)=O(E)
可以證明最多使用O(VE)次增廣 可以達到最大流,如果算法用BFS選擇增廣路徑(Edmonds-Karp算法) , 則算法的時間復雜度為O(VE2VE^2VE2)
例題:雙核CPU網絡流問題
隨著越來越多的計算機配備了雙核 CPU,TinySoft 公司的首席技術 官塞塔格利布決定更新他們著名的產品——SWODNIW。 這個例程由 N 個模塊組成,每個模塊都應該在某個內核中運行。估計了在 兩個內核上執行所有例程的成本。我們把它們定義為 Ai 和 Bi。同時,M 對模塊 需要進行數據交換。如果它們在同一個內核上運行,則可以忽略此操作的成本。 否則,就需要額外的費用。你應該明智地安排,把總費用降到最低。請寫出偽代 碼并分析算法復雜度。
這個題乍一看是一個動態規劃問題,其實還是個網絡流(二分匹配),只需要將兩個核心看作是源點和匯點,然后尋找最小割就行了
用一個割將圖一刀劈開,保證核心S和T屬于不同的劃分,且流經割的流量最小;如果兩個進程在同一個劃分,那么這兩個進程沒有任何流量會流經這個割,否則的話就要計算這個額外的流量(因為割劃斷了兩個進程之間聯系的邊),也就把這兩個節點放到了不同的CPU運行
顯然節點i不能同時屬于S和T,i要么屬于s的劃分,要么屬于T的劃分,如果屬于S的話,則i到T的邊必然被割集經過(選擇在T執行);如果屬于T的話,則i到S的邊必然被割集經過(選擇在S執行),因為割是最小割,所以任務安排的代價也是最小的,因此對于i,我們讓割經過這條邊,這條邊在兩個劃分之間
劃分割需要劃過很多邊,使得劃分的邊的總大小最小就能找到一個對進行i和j的代價最小的安排方案
割劃過的邊就是我們需要支付的代價,最小割就對應最小的代價
然后再跑一邊最大流算法就可以了
偽代碼
總結
以上是生活随笔為你收集整理的最大流 Ford-Fulkerson 算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++静态成员函数指针
- 下一篇: oracle 备份导出,oracle