题意:n点m条边,每条边有容量ci 问从s->t的最大流?
f(u,v)<=c(u,v) 流量显然要小于等于容量
f(u,v)=-f(v,u)=val 从u流val到v 等价于于 从v流-val到u (两者都使得v增加val,u减小val) ,或者说u->v流量的减小等价于v->u流量的增加
关于f的残余网络Gf: 其容量c'(u,v)=c(u,v)-f(u,v) 表示该弧还可以增加的流量
若原图G中 若c(v,u)=0 则c'(v,u)=0-f(v,u)=f(u,v) 表示原图u->v弧上可以减少的流量
则Gf上的增广路 都能在G中找到对应的增广路
Ford-Fulkerson
步骤1:任意取一个可行流为f
步骤2:构造关于f的残余网络Gf,在Gf上寻找增广路.
步骤3:重复步骤2,直到不存在增广路,则当前流为最大流
求增广路用的是Edmonds-Karp算法 时间复杂度为O(VE^2)
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=3e2+20;
const ll inf=2e15;
ll n,m,g[N][N];
ll path[N],flow[N],start,end;
queue<int> q;
ll bfs()
{
while(!q.empty())
q.pop();
memset(path,-1,sizeof(path));
path[start]=0,flow[start]=inf;
q.push(start);
while(!q.empty())
{
int t=q.front();
q.pop();
if(t==end)
break;
for(int i=1;i<=m;i++)
{
if(i!=start && path[i]==-1 && g[t][i])
{
flow[i]=min(flow[t],g[t][i]);
q.push(i);
path[i]=t;
}
}
}
if(path[end]==-1)
return -1;
return flow[end];
}
ll Edmonds_Karp()
{
ll mx_flow=0,step,now,pre;
while((step=bfs())!=-1)//找不到增广路退出
{
mx_flow+=step;
now=end;
while(now!=start)
{
pre=path[now];
g[pre][now]-=step;//更新正向边容量
g[now][pre]+=step;//更新反向边(Gf走反向边 相当于在G中减小该边流量)
now=pre;
}
}
return mx_flow;
}
int main()
{
while(cin>>n>>m)
{
int u,v;
ll c;
memset(g,0,sizeof(g));
for(int i=0;i<n;i++)
{
scanf("%d%d%I64d",&u,&v,&c);
g[u][v]+=c;
}
start=1,end=m;
printf("%I64d\n",Edmonds_Karp());
}
return 0;
}