网络流——最大流问题 EK算法
题
题:就像水从 s 流到 t ,给你每条边能流过的大小,问你 s —>t 最大能流多少?这就是最大流问题。
增广路算法
增广路算法,就是随便找 s->t的一条路,然后改变流过边的流量,再找另一条路直到找不到路
算法过程如下图(图片来自http://blog.csdn.net/yiqingnian28/article/details/23388633 博客)
看着这个图片很可能不知道为什么要加一条反向边 ?这是为了避免这种情况
当走1 -> 2 ->3 ->4 这条路时会把1-> 3->4堵上这样求出的就成 1了,很明显这是错的,于是加了一条反向边(相当于减去一条正向流量)3 -> 2 ;这样就成了1 -> 2 ->3 ->4 1-> 3 ->2 ->4
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 2009 //边的两倍
#define maxnn 20 //点
struct node
{
int v,next,c,f;
// c 容量 f流量
};
int head[maxn];
int o;
node edg[maxn];
inline void add(int u,int v,int val) //邻接表
{
edg[o].v=v;
edg[o].next=head[u];
edg[o].f=0;
edg[o].c=val;
head[u]=o++;
}
void intt()
{
memset(head,-1,sizeof(head));
o=0;
}
int max_flow(int s,int t)
{
int flow=0; //流
int a[maxnn]; //记录流过点的值
int p[maxnn]; //记录父节点 用于回溯
while(1)
{
memset(a,0,sizeof(a));
queue<int>q;
while(!q.empty()) q.pop();
q.push(s);
a[s]=inf; //起始点为无限大
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=edg[i].next)
{
if(!a[edg[i].v]&&edg[i].c>edg[i].f) //必须容量大于流量才能流
{
p[edg[i].v]=i;
a[edg[i].v]=min(a[u],edg[i].c-edg[i].f); //能经过该点的一条路的流量
q.push(edg[i].v);
}
}
if(a[t]) break; //如果流到了汇点 结束
}
if(!a[t]) return flow; //如果没有能扩冲的 结束
for(int i=t; i!=s; i=edg[p[i]^1].v) //更改流过的点的流量
{
edg[p[i]].f+=a[t];
edg[p[i]^1].f-=a[t];
}
flow+=a[t]; //流入汇点的
}
return flow;
}
int main()
{
int tt;
cin>>tt;
int js=1;
while(tt--)
{
intt();
int n,m;
cin>>n>>m;
for(int i=0; i<m; i++)
{
int u,v,val;
cin>>u>>v>>val;
add(u,v,val);
add(v,u,0);
}
cout<<"Case "<<js++<<": "<<max_flow(1,n)<<endl;
}
return 0;
}