最大流(一)—— Edmond-Karp算法

EK算法为最短增广路算法,具体步骤:

1)初始化网络中所有边的容量 c < u , v > 为该边的容量,同时反向边 c < v , u > 为0,初始化最大流为0。

2)在残留网络中找一条从源S到汇T的增广路p。如果能找到,转步骤(3);如果不能找到,则转步骤(5)。

3)在增广路p中找到所谓的“瓶颈”边,即路径中的最小边,记录下这个值X,并且累加进最大流。

4)将增广路中所有的 c < u ,v > 减去X,所有 c < v , u > 加上X,构成新的残留网络。转步骤(2)。

5)得到网络的最大流,退出。

在点数较少时比较有利

时间复杂度:O(n*m^2)

空间复杂度:O(n^2)

EK算法代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=110;     ///最大点个数
const int inf=0x7fffffff;
int mp[maxn][maxn],n,p[maxn];
bool vis[maxn];
///mp:邻接矩阵
///p:点的前驱
///vis:找增广路时用于避免增广点的重复选取
bool EK_Bfs(int st,int ed) {
    queue<int>que;
    for(int i=0;i<=n;i++) p[i]=-1,vis[i]=false;  ///初始化
    que.push(st);
    vis[st]=true;
    while(!que.empty()) {
        int e=que.front();
        if(e==ed) return true;  ///到达ed点,说明增广路已经找到
        que.pop();
        for(int i=1;i<=n;i++) {
            if(mp[e][i]&&!vis[i]) {    ///如果当前边有流且增广点未标记
                vis[i]=true;
                p[i]=e;        ///记录增广点前驱点
                que.push(i);

            }
        }
    }
    return false;       ///找不到增广路
}
int EK_Max_Flow(int st,int ed) {
    int max_flow=0;     ///最大流量
    while(EK_Bfs(st,ed)) {  ///只要能找到从st到ed的增广路,就继续循环
        int minn=inf;
        int u=ed;
        while(p[u]!=-1) {       ///找出增广路中的“瓶颈”边
            minn=min(mp[p[u]][u],minn);
            u=p[u];
        }
        max_flow+=minn;     ///累加进最大流
        u=ed;
        while(p[u]!=-1) {   ///修改路径上的边容量
            mp[p[u]][u]-=minn;
            mp[u][p[u]]+=minn;
            u=p[u];
        }
    }
    return max_flow;
}
int main()
{
    int m,st,ed;      ///m:边数目  st:起点  ed:终点
    cin>>n>>m;          ///因为懒得打所以用c++的输入输出流,提交代码不建议使用
    cin>>st>>ed;
    for(int i=1;i<=m;i++) {
        int u,v,w;
        cin>>u>>v>>w;
        mp[u][v]+=w;     ///建立u到v的权值为w的边
        mp[v][u]=0;     ///可写可不写,写上为了更好的理解
    }
    cout<<EK_Max_Flow(st,ed)<<endl;
    return 0;
}
///时间复杂度:O(n*m^2)
///空间复杂度:O(n^2)

  

posted @ 2019-07-17 11:10  wuliking  阅读(444)  评论(0编辑  收藏  举报