學習這個演算法是為學習影象處理中的圖割演算法做準備的。
基本概念:
1.最大流是一個有向圖。
2.一個流是最大流,當且僅當它的殘餘網路中不包括增廣路徑。
3.最小割就是網路中所有割中值最小的那個割,最小割是不唯一的,不過最小割的值是唯一的。
4.最大流的流量等於某一最小割的容量。
演算法思想就是Ford-Fulkerson方法。
具體流程:
1.首先使用廣度優先搜尋找到源節點到匯節點的一條路徑,為增廣路徑。
2.如果找不到新的從源到匯的增廣路徑,則上一次求得的網路就是最大流,否則向下執行。
3.找出增廣路徑中最小的路徑的值。
5.用路徑中最小的值構造最大流網路,原網路包含這個網路。
4.將增廣路徑中所有的路徑減去最小路徑這個值,形成新的網路圖。
6.對新的網路圖繼續執行第1步。
網路圖如下,沒什麼好辦法形象表示。我比較懶,不想畫圖了,真想看明白過程就看演算法導論405頁。
原網路:
最大流:
matlab程式碼如下:
clear all;close all;clc %初始化鄰接壓縮表,演算法導論405頁的圖 b=[1 2 16; 1 4 13; 2 3 12; 2 4 10; 3 4 9; 3 6 20; 4 2 4; 4 5 14; 5 3 7; 5 6 4]; m=max(max(b(:,1:2))); %壓縮表中最大值就是鄰接矩陣的寬與高 A=compresstable2matrix(b); %從鄰接壓縮表構造圖的矩陣表示 netplot(A,1); maxflow=zeros(m,m); while 1 %下面用廣度優先搜尋找增廣路徑 flag=[]; %相當於closed表,已訪問過的節點 flag=[flag 1]; head=1; tail=1; queue=[]; %佇列,相當於open表,將要訪問的節點 queue(head)=1; head=head+1; pa=zeros(1,m); %每個節點的前趨 pa(1)=1; %源節點前趨是自己 while tail~=head %廣度優先搜尋,具體細節就不註釋了 i=queue(tail); for j=1:m if A(i,j)>0 && isempty(find(flag==j,1)) queue(head)=j; head=head+1; flag=[flag j]; pa(j)=i; end end tail=tail+1; end if pa(m)==0 %如果搜尋不到匯節點,退出迴圈 break; end path=[]; i=m; %從匯節點開始 k=0; %路徑包含的邊的個數 while i~=1 %使用前趨構造從源節點到匯節點的路徑 path=[path;pa(i) i A(pa(i),i)]; %存入路徑 i=pa(i); %使用前趨表反向搜尋,借鑑Dijsktra中的鬆弛方法 k=k+1; end Mi=min(path(:,3)); %尋找增廣路徑中最小的那條邊 for i=1:k A(path(i,1),path(i,2))=A(path(i,1),path(i,2))-Mi; %增廣路徑中每條路徑減去最小的邊 maxflow(path(i,1),path(i,2))=maxflow(path(i,1),path(i,2))+Mi; %最大流,原網路包含這個網路,我只能這樣表示了 end %使用新的圖A進入下一迴圈,從新開始找增廣路徑 end figure; netplot(maxflow,1)
這裡沒有連通的路徑值為0.