)最大流演算法

來源:互聯網
上載者:User

原帖連結http://www.cnblogs.com/zhuangli/archive/2008/08/01/1258417.html

1.    最大流最小割定理介紹:

把一個流網路的頂點集劃分成兩個集合S和T,使得源點s ∈S且匯點t ∈T,割(S,T)的容量C(S,T) =∑Cuv, 其中u∈S且v∈T。

從直觀上看,截集(S,T)是從源點s到匯點t的必經之路,如果該路堵塞則流從s無法到達t。於是我們可以得到下面的定理:

 

最大流最小割定理:

任意一個流網路的最大流量等於該網路的最小的割的容量。

 

這個定理的證明這裡就不給出了,可以參考圖論方面的資料。

 

2.    求最大流的Edmonds-Karp演算法簡介:

 

若給定一個可行流F=(Fij),我們把網路中使Fij=Cij的弧稱為飽和弧,Fij<Cij的弧稱為未飽和弧。如果流網路中從i到j沒有弧,我們添加一條從i到j且容量Cij=0的弧,這樣整個流網路變成一個完全圖。如果從i到j有流量Fij,則從j到i的流量定義為Fji = -Fij 。考慮一條從源點s出發到匯點t的路徑p,如果對於每一段弧(i,j)屬於p都有Fij < Cij,即每一條屬於p的弧都是未飽和弧,則我們可以向這條路徑上壓入更多的流,使得其中的一條弧達到飽和。這樣的路徑p叫做可改進路,可壓入的流量叫做該可改進路的可改進流量。重複這個過程,直到整個網路找不到一條可改進路,顯然這時候網路的流量達到最大。Edmonds-Karp演算法就是利用寬度優先不斷地找一條從s到t的可改進路,然後改進流量,一直到找不到可改進路為止。由於用寬度優先,每次找到的可改進路是最短的可改進路,通過分析可以知道其複雜度為O(VE2)。

 

Edmonds-Karp演算法的虛擬碼如下:

 

設隊列Q--儲存當前未檢查的標號點,隊首節點出隊後,成為已檢查的標點;

path -- 儲存當前已標號可改進路經;

 

repeat

       path置空;

       源點s標號並進入path和Q;

       while  Q非空  and  匯點t未標號 do

              begin

                     移出Q的隊首頂點u;

                     for 每一條從u出發的弧(u,v) do

                            if  v未標號 and 弧(u,v)的流量可改進

then v進入隊列Q和path;

              end while

       if 匯點已標號

then 從匯點出發沿著path修正可改進路的流量;

until 匯點未標號;

 

Edmonds-Karp演算法有一個很重要的性質:當匯點未標號而導致演算法結束的時候,那些已經標號的節點構成集合S,未標號的節點構成集合T,割(S,T)恰好是該流網路的最小割;且這樣求出的最小割(S,T)中集合S的元素數目一定是最少的。

 

尋找最大流的基本方法是Ford-Fulkerson方法,該方法有多種實現,其基本思想是從某個可行流F出發,找到關於這個流的一個可改進路經P,然後沿著P調整F,對新的可行流試圖尋找關於他的可改進路經,如此反覆直至求得最大流。現在要找最小費用的最大流,可以證明,若F是流量為V(F)的流中費用最小者,而P是關於F的所有可改進路中費用最小的可改進路,則沿著P去調整F,得到的可行流F'一定是流量為V(F')的所有可行流中的最小費用流。這樣,當F是最大流時候,他就是所要求的最小費用最大流。

 

注意到每條邊的單位流量費用B(i,j)≥0,所以F=0必是流量為0的最小費用流,這樣總可以從F=0出發求出最小費用最大流。一般的,設已知F是流量V(F)的最小費用流,餘下的問題就是如何去尋找關於F的最小費用可改進路。為此我們將原網路中的每條弧<u,v>變成兩條方向相反的弧:

 

1。前向弧<u,v>,容量C和費用B不變,流量F為0;

2。後向弧<v,u>,容量C為0,費用為-B,流量F為0;

 

每一個頂點上設定一個參數CT,表示源點至該頂點的通路上的費用和。如果我們得出一條關於F的最小費用可改進路時,則該路上的每一個頂點的CT值相對於其它可改進路來說是最小的。每一次尋找最小費用可改進路時前,源點的CT為0,其它頂點的CT為+∞。

 

設cost為流的運輸費用,初始時由於F=0,則cost=0,我們每求出一條關於F的最小費用可改進路,則通過cost ← cost + ∑B(e)*d, (其中e∈P,d為P的可改進量)來累積流的運輸費用的增加量。

 

顯然,當求出最小費用最大流時,cost便成為最大流的運輸費用了。

 

另外設定布爾變數break為最小費用可改進路的延伸標誌,在搜尋了網路中的每一個頂點後,若break=true表示可改進路還可以延伸,還需要重新搜尋網路中的頂點;否則說明最小費用的可改進路已經找到或者最大流已經求出。

 

 

 

本人說明:

 

這個模版的代碼完全按照BFS從源點逐個遍曆增廣路徑,得到最大增廣容量,通過不斷調整,最後求得最大流量,值得注意的是,最後一次BFS後所標的路線即為最小截集,即所謂的瓶頸,據此很容易求出最小截集的容量。

 

 

 

#include <iostream>
#include <queue>
using namespace std;
//鄰接陣實現
const long MAXN=1000;
const long lmax=0x7FFFFFFF;
long Net[MAXN][MAXN];//殘餘網路
long Path[MAXN];//增廣路徑
long Lv[MAXN];//增廣路徑通過容量
queue<long> q;
long m,n;//點,邊
long Start,End;

void init()
{
    while (!q.empty())
    {
        q.pop();
    }
    memset(Path,-1,sizeof(Path));
}

long Min(long a,long b)
{
    return a<b?a:b;
}

long bfs()
{
    init();
    Path[Start]=0;
    Lv[Start]=lmax;

    q.push(Start);

    while (!q.empty())
    {
        long t=q.front();
        q.pop();

        if (t==End)
        {
            break;
        }

        long i;
        for (i=1;i<=m;++i)
        {
            if (i!=Start&&Path[i]==-1&&Net[t][i])
            {
                Lv[i]=Min(Lv[t],Net[t][i]);
                q.push(i);
                Path[i]=t;
            }
        }
    }

    if (Path[End]==-1)
    {
        return -1;
    }

    return Lv[m];
}

void print(long n)
{
    printf("%ld/n",n);
}

void Ford_Fulkerson()
{
    long i;
    long Max_Flow=0;


    for (i=0;i<n;++i)
    {
        long from,to,cost;
        scanf("%ld %ld %ld",&from,&to,&cost);
        Net[from][to]=cost;//cost為剩餘量
        //如果在現有網路上擴充 剩餘量為容量-已佔用量
        //最大流結果要加上已流入的量
    }

    scanf("%ld %ld",&Start,&End);

    long step;
    while ((step=bfs())!=-1)//反搜增廣路徑並調整流量
    {
        Max_Flow+=step;
        long now=End;
        while (now!=Start)
        {
            long pre=Path[now];
            Net[pre][now]-=step;
            Net[now][pre]+=step;
            now=pre;
        }
    }

    print(Max_Flow);
}



int main()
{

    while (scanf("%ld %ld",&m,&n)!=EOF)
    {
        Ford_Fulkerson();
    }
    return 0;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.