Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 58912 | Accepted: 22614 |
Description
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
Input
Output
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50
网络流陆续搞了好几次,看了好多资料,终于搞明白了。这里先讲一下Ford-Fulkerson,之前被一些资料误导,Ford-Fulkerson写的是Edmonds_Karp算法,当要学习Edmonds_Karp算法时,发现这两个算法怎么没有区别?
后来在看了大量资料从字里行间体会出来,其实Ford-Fulkerson只是一种思想,还称不上算法,思想里包含一个找增广路过程,但没有规定如何找增广路,因此假设最大流为U,而每次增广1点流量,那么需要增广U次,每次增广需要遍历整幅图O(m+n),总复杂度O((m+n)U),当U较大时,这种随意找增广路算法就不可行了。
于是,就有人提出利用BFS来找增广路,就是Edmonds_Karp算法,所以Edmonds_Karp算法就是规定了Ford-Fulkerson找增广路的方法,仅此而已。
但这么一修改,复杂度发生了惊人的变化。
在说明Edmonds_Karp的复杂度为O(n*m^2)前,希望你已经提前知道了一些基本概念,如层次网络。
Edmonds_Karp本质是什么?不就是最短增广路算法,为什么最短,显然这是由BFS的性质决定的。
大家知道层次网络中只有第i层指向第i+1层的边,假设边(u,v),那么d[u]+1=d[v],又在层次网络中找到一条增广路,(u,v)是该增广路上权值最小的边(称作关键边),也就是这条增广路的可增广量,一经增广这条边将在层次网络中消失,于此同时会产生反向边(v,u),现在我们来考虑(u,v)总共可以成为 多少次关键边。从上面描述中可知,关键边一经增广就消失(流量为0),那如何才能再成为一次关键边,显然当(v,u)增广时,会导致(u,v)的流量增加,这样(u,v)将有资格再次成为键边。
我们来看两个等式d[u]+1=d[v],d[v']+1=d[u']{反向边(v,u)在层次网络中的等式}
注意:后一个等式增广晚于前一个,所以增广路增长(这就是最短增广路的本质,可以证明)。也就是d[v']>d[v],代入可得:
d[u']=d[v']+1>d[v]+1=d[u]+2,这个说明一条边前后两次成为关键边,u的层次会增加2,而u的层次至多从2变到n-1(u不会是源点和汇点),因此(u,v)最多有(n-2)/2次能够成为关键边,整个层次网络最多O(m)条边,因此关键边条数O(mn),而每找到一条增广路就会有一条关键边消失,因此最多有O(mn)条增广路,也就是BFS的执行次数最多为O(mn)次,而BFS的复杂度可认为O(m),因此总复杂度O(n*m^2),具体实现过程可以参考其他资料,比较简单的!
#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 210
using namespace std;
const int inf=0x3f3f3f3f;
int cap[Maxn][Maxn]; //边容量
int flow[Maxn][Maxn]; //边实际流量
int pre[Maxn]; //增广路节点前驱
int alpha[Maxn]; //改进量
int q[Maxn]; //队列
int m,n; //边,节点数
void init(){
memset(cap,0,sizeof cap);
memset(flow,0,sizeof flow);
}
int Edmonds_Karp(int src,int t){ //源点,汇点
int maxflow=0;
while(1){
memset(alpha,0,sizeof alpha);
alpha[src]=inf; //源点初始化无穷大
pre[src]=-1;
int s=0,e=-1;
q[++e]=src;
while(s<=e&&!alpha[t]){ //bfs找增广路
int u=q[s++];
for(int i=1;i<=n;i++){
if(!alpha[i]&&flow[u][i]<cap[u][i]){
pre[i]=u;
alpha[i]=min(alpha[u],cap[u][i]-flow[u][i]);
q[++e]=i;
}
}
}
if(!alpha[t]) break; //找不到增广路
int k=t;
while(pre[k]!=-1){
flow[pre[k]][k]+=alpha[t];
flow[k][pre[k]]-=alpha[t];
k=pre[k];
}
maxflow+=alpha[t];
}
return maxflow;
}
int main()
{
int u,v,c;
while(~scanf("%d%d",&m,&n)){
init();
while(m--){
scanf("%d%d%d",&u,&v,&c);
cap[u][v]+=c;
}
printf("%d\n",Edmonds_Karp(1,n));
}
return 0;
}