matlab練習程式(最大流/最小割)

Dsp Tian發表於2013-07-12

學習這個演算法是為學習影象處理中的圖割演算法做準備的。

基本概念:

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.

相關文章