这是我参与「第四届青训营 」笔记创作活动的第3天

219 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第3天

Edmonds–Karp Algorithm

图片.png

这节课简单介绍 Edmonds-Karp 算法,由 Edmonds 和 Karp 两人在 1972 年提出。Edmonds-Karp 算法是 Ford-Fulkerson 算法的一种特例,一定能找到最大流。Edmonds-Karp 算法的时间复杂度低于 Ford-Fulkerson 算法。 课件: github.com/wangshusen/… 参考文献: 1. L. R. Ford and D. R. Fulkerson. Maximal flow through a network. Canadian Journal of Mathematics, 8: 399–404, 1956. 2. J. Edmonds and R. M. Karp. Theoretical improvements in algorithmic efficiency for network flow problems. Journal of the ACM. 19 (2): 248–264, 1972.

这是我做的第⼀道最⼤流的题 HDU1532(最⼤流EK算法模板题) ,我这题是⽤EK算法写的,EK算法最关键的地⽅在于反向边的建⽴,这⾥也不好理解,为什么要建⽴反向边。⾸先我们假设没有反向边的情况,如有⼀条路径从源点到汇点,那么这条路径上我们取所有边的最⼩值,然后让这个最⼩值的流从源点流到汇点,这样⼀定是能够满⾜所有边的要求(因为我们找的是这条路径上最⼩的),这样我们就增加了从源点到汇点的流,但是现在我们要求⼀个最⼤流,所以我们希望有更多这样的路径,所以当我们找完所有的路径之后,得到的流就是最⼤流。但是,我们找每条路径时,每次都是随机找⼀条路径,所以会导致⼀个情况,就是找了这条路径之后,会对后⾯的路径有影响,导致最后得到的流的和并不是最⼤,在这⾥我画了⼀个图帮助理解。⽐如这个图,边的权值都为1

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
int dp[100][100],pre[100];
const int tmin=999999999;
int maxflow;
void EK(int start,int end,int n){
    while(1){
        queue<int>q;
        q.push(1);//源点为1,进队
       int  minflow=tmin;
        memset(pre,0,sizeof(pre));//初始化增广路径数组,题目中的顶点是从1开始的
        while(!q.empty()){//bfs找增广路
            int u=q.front();
            q.pop();
            for(int i=1;i<=n;i++){
                if(dp[u][i]>0&&!pre[i]){//pre[i]除了记录当前顶点的父亲,还记录当前顶点有没被访问过
                    pre[i]=u;
                    q.push(i);
                }
            }
        }
        if(pre[end]==0)//顶点的父亲为空,表示找不到增广路,很容易理解吧。。
            break;
        for(int i=end;i!=start;i=pre[i]){//找出增广路中最小残余量
            minflow=min(dp[pre[i]][i],minflow);
        }
        for(int i=end;i!=start;i=pre[i]){//更新增广路中正反向弧的流量
            dp[pre[i]][i]-=minflow;
            dp[i][pre[i]]+=minflow;
        }
        maxflow+=minflow;
    }
}
int main(){
   int count=0;
   int n,m;
   int t;
   scanf("%d",&t);
   while(t--){
        scanf("%d%d",&n,&m);
       memset(dp,0,sizeof(dp));
       memset(pre,0,sizeof(pre));
       count++;
       int u,v,w;
       for(int i=1;i<=m;i++){
           scanf("%d%d%d",&u,&v,&w);
           dp[u][v]+=w;
       }
       maxflow=0;
       EK(1,n,n);
       printf("Case %d: %d\n",count,maxflow);
   }
   return 0;
}

模板来源:www.cnblogs.com/13224ACMer/…