通俗易懂的方式講解最大流和最小割問題

最大流問題:
在這裏插入圖片描述
標號作用:
1)圈內的標號,爲點的代號,如s,t;
2)邊上的標號,如3/0:3爲容量,表示兩個點之間最大流通量;0爲當前實際流通量。

問題:我們想要讓水從s流向t,那麼最大有多少水能流到t呢?
在這裏插入圖片描述
先粗略一看,水要從s到t肯定要經過(1,t),(2,t)這兩條通道;那麼受這兩條管道的限制只能流過3+2=5ml水,但因爲流水量還受前面的管道的限制,所以這兩條管道的實際流水量並不一定等於2+3=5ml;所以我們要求出從s到t的最大流水量,我們就需要求出流過(1,t),(2,t)這兩條通道的水量,即流入t的實際流水量;

求解步驟很簡單:
1)、先在(s,1,t)這條路線流過3ml:
在這裏插入圖片描述
2)、再往(s,2,t)流過2ml:
在這裏插入圖片描述
可見,不能再流更多的水過去了,因此最大流通量爲3+2=5ml;

2、接下來我們嘗試再換個方式計算:
1)、先在(s,1,t)流過2ml;
2)、再(s,1,2,t)流過1ml;
3)、再(s,2,t)流過1ml;
現在的情況是下面這樣的:
在這裏插入圖片描述
可見,現在的情況還沒有達到最大流通量,那我們可以接着這樣做:
4)、走(s,2,1,t)流過1ml;
解釋:但是你會很奇怪,明明(1,2)這個通道已經被使用了啊?但其實我們走的是(2,1)這條通道,那我們怎麼能反着箭頭走呢?其實這就相當於把原來(1,2)方向通道內的水退回去了,退到點(1)處。
下面我們一步步完成(s,2,1,t)流過1ml這個過程:
這1ml水先流過(s,2)到達結點(2),再讓(1,2)這條通道的水退到結點(1)去,往(1,t)走,這個時候由於(1,2)少了1ml水往這走,那麼自然這1ml水也沒有到達(2,t)這個通道,那麼(2,t)當前通道的流通量減爲1,還可以通過1ml,所以結點2的水可以走(2,t)到達t。
在這裏插入圖片描述
可以發現,最後的結果相同,最大流也爲3+2=5;

那麼我們可以總結一下,以上兩個方法其實都是在尋找所有的增廣鏈路,當找不到任何一條增廣鏈路的時候,我們就能求出最大流通量。

所以接下來我們要引入幾個概念:
鏈路:從兩個頂點之間沒有重複邊的路徑。
前向邊:與鏈路方向一致的邊,即你在這條邊上想要的走向與邊的箭頭方向一致。
後向邊:與鏈路方向相反的邊。
增廣鏈路:鏈路中所有前向邊的當前流通量小於這條邊的容量,即處於可以流通的狀態,通道沒有達到飽和;並且所有後向邊的當前流通量大於0,即處於有水流過的狀態。
可能,看了這些概念,你仍然想問那什麼是增廣鏈路呢?什麼是前向邊,後向邊呢?我們重新來過一次找從s到t的路徑的過程;
在這裏插入圖片描述
從這幅圖可以看到,每一條路都沒有被佔用,我們走(s,1,t),(s,2,t),(s,1,2,t)這三條鏈路都能到達t,那麼這三條路就是增廣鏈路了。那用概念怎麼理解呢?(s,1),(1,t),(s,2),(2,t),(1,2)這些就是當前所有增廣鏈路中的前向邊,(1,s),(t,1),(2,s),(t,2),(2,1)這些就是後向邊。可見,這三條增廣鏈路的所有邊都是由前向邊構成的,並且前向邊的容量大於實際流通量0,可以流過水,即處於流通狀態。

那麼我們隨機選一條增廣鏈路走下去,我們選擇(s,1,2,t)流過1ml,然後更新這一條增廣鏈路上的流量。
在這裏插入圖片描述
那麼此時的增廣鏈路有哪些變化呢?此時能到達t的增廣鏈路有(s,1,t),(s,2,t),(s,2,1,t);
(s,1,t)和(s,2,t)中全是前向邊,並且都是可以流通的,因此這兩條肯定是增廣鏈路。你們比較奇怪的是爲什麼(s,2,1,t)是增廣鏈路,我們來分析一下,(s,2,1,t)中(s,2),(1,t)是可以流通的前向邊,(2,1)這條邊與箭頭方向相反,箭頭方向爲(1,2),所以(2,1)在鏈路中是反向邊,並且這條邊實際流通量大於0,這也符合增廣鏈路的定義;(s,2,1,t)這條鏈路就意味着我們可以將(1,2)這個地方的水退回到結點(1)處,讓(1,2)這個方向的水往(1,t)走,而(s,2)流過來的水代替(1,2)這個地方的水到達結點2,補充結點2失去的(1,2)通道的水。
至此,我們已經完全認識到了這幾個概念,下面討論一下實現查找增廣鏈路的算法;
以下面這幅圖爲例:
在這裏插入圖片描述
尋找增廣鏈路求最大流的算法,Ford-Fulkerson算法:
我們這個圖中共有4個頂點(s,1,2,t);
現在先給點(s)進行標號(0,+),0表示點(s)是出發點,+表示輸入的水流量爲無窮大。
而剩下的點(1,2,t)爲未標號的,如下圖所示。
在這裏插入圖片描述
接下來,我們將點分爲三類:
1)已標號已檢查的:不存在,
2)已標號未檢查的:包括點(s),
3)未標號的:包括點(1,2,t)。
然後我們從已標號未檢查的集合拿到一個點,開始遍歷整個圖:
此時這個點爲(s),對點(s)進行檢查,檢查的過程就是尋找點(s)的鄰接點並加上標號,但這些鄰接點與點(s)之間要滿足一些要求,鄰接點未標號,鄰接點與點(s)之間的邊是可以流通的前向邊(即容量大於實際流通量的前向邊),或者點之間的邊不是零流的後向邊(即實際流通量不爲0的後向邊);並且,如果符合條件的鄰接點中包含點(t),就說明找到了一條增廣鏈路,結束整個遍歷過程。可見滿足要求的點只有(1)和(2);我們對點(1)加上標號(s,3),代表從點(s)到點(1)的可流通量爲3;我們再對點(2)加上標號(s,2),代表從點(s)到點(2)的可流通量爲2;
接下來把點(s)從已標號未檢查的集合中轉移到已標號已檢查的集合中,點(1)和點(2)從未標號的集合中轉移到已標號未檢查的集合中;
現在集合中的情況:
1)已標號已檢查的:包括點(s),
2)已標號未檢查的:包括點(1,2),
3)未標號的:包括點(t)。
然後再重複上面的過程,從已標號未檢查的集合拿到一個點,繼續檢查,此刻拿到的點爲(1),對符合條件的鄰接點(t)和(2)進行標號,發現符合條件的鄰接點中包含t,所以遍歷結束,找到了一條增廣鏈路(s,1,t);
在這裏插入圖片描述
然後更新整條增廣鏈路上的流量:比較這條路上的實際流通量的最小值,這個值就是這條路上的最大流通量。圖中標號(s,3)的這個3就表示路徑(s,1)的實際流通量爲3。所以很明顯這條路做多隻能流通3,所以將0加上3,更新完畢。
在這裏插入圖片描述
這樣就找到了一條增廣鏈路了,然後我們再以這個圖爲基礎尋找下一條,但是需要重新分過類,將所有點還原至未處理過的狀態,但使用了的通道不還原。
接下來,我們將點分爲三類:
1)已標號已檢查的:不存在,
2)已標號未檢查的:包括點(s),
3)未標號的:包括點(1,2,t)。
在這裏插入圖片描述
然後要做的就是從s開始重複檢查的過程了,直至找到一條增廣鏈路。
等到所有增廣鏈路都被找出來後,將每一條增廣鏈路的最大流通量相加就是整個圖的最大流通量了。

最小割問題:割容量最小
在這裏插入圖片描述
對於上面這張圖,我們想把s,t分割開,成爲不連接的兩部分,這個很簡單,只需要斷開(1,t),(2,t)就能成功,也有許多其它辦法,例如:斷開(s,1),(s,2),或者斷開(s,1),(1,t),(2,t)。每割一條邊就會產生損耗,這個損耗就是邊的權值,我們想求出能將s,t割開的邊,並且損耗達到最小,這就是求最小割;
上面這個圖的最小割很明顯就是將(1,t),(2,t)斷開就是得到的最小割。

下面給出用最大流求最小割問題的方法:轉換原理就是最小割的代價等於最大流。
原理:當一個圖被割分成兩個部分時,不再存在S到T的通路,所以割的代價必定大於等於圖的最大流。
下面將這個原理演示一遍:
增廣鏈路無合併的情況:
在這裏插入圖片描述
如果要將s與t斷開成爲兩部分,很明顯,我們可以直接斷開(1,t),(2,t)就能做到,因爲這兩條路是從s通往t的必經之路;但我們也可以按照最大流的思想去做,有兩條增廣鏈路,(s,1,t),(s,2,t)可以通往t,我們只要把所有鏈路堵住就好了,那我們堵哪裏呢?毫無疑問,要想使得損耗最小,肯定是隻要分別堵住兩條鏈路中管道容量最小的邊即可,使得這些邊的權值的和最小,這就讓最小割的代價最小了,而每條增廣鏈路的最大流通量的權值和也是最大流通量。這就說明了最小割的代價是等於最大流通量的,所以割的代價是大於等於最大流通量的。
下面我們再考慮一下鏈路有合併的情況:
在這裏插入圖片描述
按照我們的想法:分別堵住兩條鏈路中管道容量最小的邊,我們堵住(s,1),(s,2),但此時損耗達到了1+4=5,但實際上最小損耗應切割(3,t),最小損耗明顯爲4。但儘管這樣,最小割是等於最大流在這個圖中仍然是正確的;所以,我們應該修改以下找最小割的方法,猜想一下,我們需要切割的應該是飽和邊中的幾條來達到最小割,飽和邊有(s,1),(3,t);所以我們先嚐試切割邊(s,1),形成新的圖,再從這個新的圖中求最大流b,如果這個圖的最大流與原圖a的最大流差值b-a等於被切割邊(s,1)的容量1,那麼就說明這條邊是屬於最小割集中的一條邊。很明顯b=4, a=4, a-b=0;而邊(s,1)的容量爲1,所以邊(s,1)不屬於最小割集。然後我們繼續判斷飽和邊(3,t),在原圖a上將(3,t)切除,形成新的圖c,很明顯c=0,a=4,a-c=4,符合,所以邊(3,t)屬於最小割集。遍歷集合完畢,所以這幅圖的最小割集爲{ (3,t) }

所以當找到了最大流之後,就能從飽和邊中找出最小割。最小割的值爲最大流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章