//感觉以前写的好敷衍
上次的文章绝大本分摘自别人的博客,这次我自己仔细的分析一下。
首先,简单的FolkFoukerson算法不断的增广时,可能走了太多的反向弧,即做了大量的无用功,所以我们规定了增广的一个条件——每次只增广最短的那条,那么可以保证这条增广路长度不下降,上限是O(n),如果我们简单用bfs进行增广,这就是著名的EmondKarp(EK)算法,那么整个算法的复杂度会达到(n*m^2),m可以达到n^2,即n^5,这显然很不理想。
我们再考虑一下EK算法,算法在不断BFS过程中,也重复走了太多同样的路,所以我们其实只需bfs一次,构造出一个单源最短路的层次图,那么我们接下来只需不断尝试当前层次图的最短路即可。这时由于最短路的唯一性,我们用dfs增广即可。
简单总结一下步骤:
1.BFS构造层次图,判断是否还有增广路。
2.DFS寻找增广路进行增广。
代码就不给注解了,旧版里就一个好——代码注释比较多(手动滑稽)
参考代码:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int M=210000;
const int INF=0x3f3f3f3f;
struct Edge{
int to,cap,next;
}e[M];
int a[M],level[M];
int ans=0;
int n,m,S,T,EdgeCnt=0;
queue<int> Q;
void addedge(int u,int v,int f){
int p=EdgeCnt;
e[p].to=v;e[p].cap=f;e[p].next=a[u];
a[u]=p;
EdgeCnt++;
}
bool bfs(int S){
memset(level,0xff,sizeof(level));
level[S]=0;
Q.push(S);
while (!Q.empty()){
int u=Q.front();Q.pop();
int p=a[u];
while (p!=-1){
int v=e[p].to;
if (e[p].cap>0 && level[v]==-1){
level[v]=level[u]+1;
Q.push(v);
}
p=e[p].next;
}
}
return level[T]>-1;
}
int dfs(int u,int left){
if (u==T || !Left)return left;
int p=a[u],used=0;
while (p!=-1){
int v=e[p].to;
if (e[p].cap>0 && level[v]==level[u]+1){
int w=left-used;
w=dfs(v,min(e[p].cap,w));
used+=w;
e[p].cap-=w;
e[p^1].cap+=w;
if (used==left)return left;
}
p=e[p].next;
}
return used;
}
int main(){
scanf("%d%d%d%d",&n,&m,&S,&T);
memset(a,0xff,sizeof(a));
for (int i=1;i<=m;i++){
int u,v,f;
scanf("%d%d%d",&u,&v,&f);
addedge(u,v,f);
addedge(v,u,0);
}
while (bfs(S)){
ans+=dfs(S,INF);
}
printf("%d\n",ans);
return 0;
}