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;
    }
}

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