最大流
增广路
为了解决最大流问题,再引入一个概念:剩余容量【c(x , y)-f(x , y)】
如果可以找到一条从源点出发,经过中间节点,流向汇点,且其中每一条边的剩余容量均大于0的路,就称这条路为一条增广路,假设可以知道这一条增广路中所有的边的最小剩余容量为p,那么对于整个网络系统而言,就可以增加一个流量为w的流从源点通过这一条路流向汇点,那么这个网络的流量就增加了w。
如果找到了所有的增广路,已经没有其他的增广路可以找时,就说明网络的流量达到了最大,此时的流量就是网络的最大流了
Edmonds-Karp增广路算法
Edmonds-Karp算法,简称为EK算法,就是不断的用BFS(显然这种问题中用BFS比用DFS快捷的多)找增广路,找到所有的增广路的时候就计算出网络的最大流了
当然,在这个过程中还要注意:除了考虑原图的所有边之外,还应该考虑所有边的反向边,这些边可能有些因为没有在图中输入,他们的原始容量为0,特别容易被忽略
这个意思就是:对于一条边(x , y)而言,如果在加入增广路的过程中流过了一个”流“,其剩余流量变成了c(x , y)-f(x , y),那么其反向边的流量也会发生变化,变成了c(y , x)-f(y , x)
图解:
【画的有点丑不要怪我QAQ】
代码实现:(因为还有反向边的储存,所以可以用到邻接表的”成对储存技巧“)
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int len_node = 2010;
const int len_edge = 20010; //这个是要开的数组的大小,根据题目自己定就行了
int num_node,num_edge,s,t,cnt,maxflow;
int to[len_edge],edge[len_edge],head[len_node],nxt[len_edge]; //边
int vis[len_node],minf[len_node],pre[len_node];
/*
minf: 记录每一条增广路上的最小容量
pre: 记录前驱(使得在这条增广路上每一条边由终点可以知道起点)
*/
void init(){
memset(head,0,sizeof(head));
s=1;
t=num_node;
cnt=1;
maxflow=0;
}
void addEdge(int u,int v,int w){
//有向图 存边操作
to[cnt]=v;
edge[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt++;
//成对储存
to[cnt]=u;
edge[cnt]=0;
nxt[cnt]=head[v];
head[v]=cnt++;
} //因为规定了 一对边不能同时为正 所以一条边为正 另一条边就为0
int x,y;
bool BFS(){
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(s);
vis[s]=1;
minf[s]=INF; //这个用来逐步记录这条增广路上的最小容量
while(!q.empty()){
x=q.front();
q.pop();
for(int i=head[x];i;i=nxt[i]){
if(edge[i]){
y=to[i];
if(vis[y]){
continue;
}
minf[y]=min(minf[x],edge[i]); //更新这个最小容量 这个是从一开始就开始更新的 所以经过这个过程之后 minf[t] 此时就是这一条增广路的最小容量
pre[y]=i; //记录前驱 便于找到最长路的实际方案 在update函数中发挥作用
q.push(y);
vis[y]=1;
if(y==t){
return 1; //找到了一条增广路了 直接返回 进行 update()
}
}
}
}
return 0;
}
int p,pre_p;
void update(){ //更新增广路及其反向边的剩余容量
p=t;
while(pre_p!=s){
pre_p=pre[x];
edge[pre_p] -= minf[t];
edge[pre_p^1] += minf[t];
p=to[pre_p^1];
}
maxflow+=minf[t];
}
int main(){
int a,b,c;
while(~scanf("%d%d",&num_node,&num_edge)){
init();
for(int i=1;i<=num_edge;i++){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
}
while( BFS() ){
update();
}
printf("%d\n",maxflow);
}
return 0;
}
时间复杂度:O(numNode*numEdge^2)