Edmonds-Karp
根据定义,若一条从源点S到汇点T的路径上各点的剩余容量都大于0,则称这条路径为增广路。那么就可以通过不断寻找增广路来求出最大流。
具体做法就是通过bfs寻找从S到T的增广路径,并顺便计算出最小剩余容量minx,找到后路径上各点减去minx,答案(最大流)加上minx。
需要注意的是,因为是单纯的遍历所有剩余流量大于零的边,所以无法保证当前所选的边是否是最优,所以需要一种方法可以“后悔”,即撤回之前的决定,而这种“后悔”的方法就是退流,即在遍历时除了考虑当前遍历的边以外,还需要考虑每条边的反向边。
具体实现时,我们按照邻接表成对储存技巧,在存储边时下标从2开始,那么反向边和边之间可以通过xor 1来转换。
代码如下
#include<bits/stdc++.h>
using namespace std;
int n,m,S,T,linkk[205],t=1;
int q[505],head,tail;
int before[205],minx[205];
long long ans=0;
struct node{
int y,v,n;
}e[405];
bool vis[205];
inline int read(){
int NUM=0,f=1;
char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())
NUM=(NUM<<1)+(NUM<<3)+c-48;
return NUM*f;
}//快读
void insert(int xx,int yy,int zz){
e[++t].y=yy;
e[t].v=zz;
e[t].n=linkk[xx];
linkk[xx]=t;
e[++t].y=xx;
e[t].v=0;
e[t].n=linkk[yy];
linkk[yy]=t;
return;
}//正反存边
void init(){
n=read();m=read();S=read();T=read();
for(int i=1;i<=n;++i){
int x,y,z;
x=read();y=read();z=read();
insert(x,y,z);
}
return;
}
void Up(){
int now=m;
while(now!=S){
int i=before[now];
e[i].v-=minx[m];
e[i^1].v+=minx[m];
now=e[i^1].y;
}
ans+=minx[m];
return;
}
bool BFS(){
memset(vis,0,sizeof(vis));
head=1;tail=0;
q[++tail]=S;
vis[S]=1;
minx[S]=1e9;
for(;head<=tail;++head){
int x=q[head];
for(int i=linkk[x];i;i=e[i].n){
if(!e[i].v)continue;
int y=e[i].y;
if(vis[y])continue;
vis[y]=1;
minx[y]=min(minx[x],e[i].v);//更新最小剩余容量
q[++tail]=y;
before[y]=i;
if(y==T) return 1;//遍历到终点,找到一条路径
}
}
return 0;
}
void work(){
while(BFS())Up();
cout<<ans;
return;
}
int main(){
init();
work();
return 0;
}