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)