Edmonds-Karp算法,網絡流最大流

     網絡流是一種生活中常見的圖模型,包含一個起始點,和一個匯點,以及若干結點,用有向邊連接,每條邊的權值代表能流經該邊的最大流量。生活中,水流網絡,電流網絡,信息網絡這些問題都能描述成網絡流。網絡流中一種常見的問題是最大流問題。即求從起始點到達匯點流的最大值。在《算法導論》介紹了Edmonds-Karp算法,該算法運行時間在圖G=(V,E)上爲O(VE),基於BFS實現。

     實現過程是從殘存網絡中找到一條最短的增廣路徑,對路徑上的邊做增廣操作,並改變一些數據,直到殘存網絡中不在存在增廣路徑。

     殘存網絡簡單來講就是在每次增加操作結束後得到的網絡,原本在網絡流中不允許出現平行反向的邊(若map[u][v]爲網絡流中的一條邊,那麼網絡流中必然不存在map[v][u],map[v][u]爲map[u][v]的平行反向邊,畫圖的話會很好理解)。但是在殘存網絡中需要加入反向平行邊(如果有必要)。每條邊的權值表示可通過該邊的流量,那麼在殘存網絡中,反向平行邊的權值代表的是原本已經流過該邊的流量。例如:f[u][v]=x代表已經流過該邊的流量,那麼,map[v][u]的權值就爲f[u][v]。可以看出,未做任何操作的流網絡也是一個殘存網絡。

增廣路徑就是在殘存網絡中可以從起始點走到匯點(想了一下,可能叫目標點會更好理解?)的一條簡單路徑。如圖,1-->2-->4-->6爲一條增廣路徑。


     接下來就是每次找到增廣路徑以後對路徑上每條邊做處理了c[u][v]代表邊uàv的能通過的最大流量或者叫做容量。首先需要找到該路徑的增加流量,該流量值爲該路徑上所有邊中殘存流量的最小值,這是保證可以通過該路徑的最大流量值。接下來需要縮減通過該邊的容量,同時需要增加平行反向邊的容量。記增加流量爲p,那麼u-->v爲該路徑上的邊。c[u][v]-=p;c[v][u]+=p。

按照這樣的操作直到不存在增廣路徑。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int path[1000005],flow[1000005];
int map[1005][1005],que[1000005];
int n,m;

int BFS(int start,int des)
{
    int head,tail;
    memset(que,0,sizeof que);
    for (int i=1;i<=n;i++)
    {
        path[i]=-1;
    }
    path[start]=0;
    flow[start]=0x3f3f3f3f;
    head=tail=0;
    que[head++]=start;
    while (head>tail)
    {
        int u=que[tail++];
        if (u==des)
            break;
        for (int i=1;i<=n;i++)
        {
            if (i!=str&&path[i]==-1&&map[u][i]>0)
            {
                path[i]=u;
                flow[i]=min(map[u][i],flow[u]);
                que[head++]=i;
            }
        }
    }
    if (path[des]==-1)
        return -1;
    return flow[des];
}


int maxflow(int start,int des)
{
    int sum=0,increase=0;
    while ((increase=BFS(start,des))!=-1)
    {
        int k=des;
        while (k!=start)
        {
            int pre=path[k];
            map[pre][k]-=increase;
            map[k][pre]+=increase;
            k=pre;
        }
        sum+=increase;
    }
    return sum;
}

int main()
{
    int start,end,f;
    while (cin>>n>>m)  
    {
        memset(map,0,sizeof map);
        for (int i=0;i<m;i++)
        {
            cin>>start>>end>>f;
            map[start][end]+=f;
        }
        cin>>start>>end;
        int ans=maxflow(start,end);
        cout<<ans<<endl;
    }
}

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