最大流(一)—— 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)
所谓人生,一半惊喜,一半遗憾