Description
Every time it rains on Farmer John’s fields, a pond forms over
Bessie’s favorite clover patch. This means that the clover is covered
by water for awhile and takes quite a long time to regrow. Thus,
Farmer John has built a set of drainage ditches so that Bessie’s
clover patch is never covered in water. Instead, the water is drained
to a nearby stream. Being an ace engineer, Farmer John has also
installed regulators at the beginning of each ditch, so he can control
at what rate water flows into that ditch. 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
The input includes several cases. For each case, the first line
contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M
<= 200). N is the number of ditches that Farmer John has dug. M is the
number of intersections points for those ditches. Intersection 1 is
the pond. Intersection point M is the stream. Each of the following N
lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei
<= M) designate the intersections between which this ditch flows.
Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <=
10,000,000) is the maximum rate at which water will flow through the
ditch.
Output
For each case, output a single integer, the maximum rate at which
water may emptied from the pond.
Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50
思路
这是一道最大流的模板题,给你m条边和n个点,然后给出每个边的两点以及权值,求最大流。
关于网络流的定义不多说,很多资料都有。说一下具体的思想,思想就是:
首先我们要有三个概念:
- 实流网络:只显示每条边的实际流量,不显示容量
- 残余网络:在残余网络中,与网络边对应的同向边是可增量(还可以增加多少流量),反向边是实际流量
- 可增广路:在残余网络中,一条从源点到汇点的简单路径
福特-福克森算法的思想是对于一个残余网络,不断地寻找可增广路,然后把每次的可增广量累加起来,就是最后的最大流。
- 增广路定理:设
flow
是网络G
的一个可行流,如果不存在从源点s
到汇点t
关于flow
的可增广路p,则flow
是G
的一个最大流。
那么EK算法解决的问题自然就是寻找增广路的过程了,如果寻找增广路的过程用的算法不对的话,那么时间复杂度就会很高,实质上,EK算法
就是利用广度优先搜索来遍历一个图,然后用一个数组pre
来记录一个点的前驱,然后寻找增广路,在实流网络中增流,在残余网络中减流,最后累加的可增广量就是答案。
代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
const int N=200+20;
int g[N][N],f[N][N],pre[N];//分别代表残余网络,实流网络,前驱数组
bool vis[N];//标记数组
int n,m;//点数和边数
bool bfs(int s,int t)
{
mem(pre,-1);
mem(vis,false);
queue<int>q;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=1; i<=n; i++)
{
if(!vis[i]&&g[now][i]>0)
{
vis[i]=true;
pre[i]=now;
if(i==t)
return true;
q.push(i);
}
}
}
return false;
}
int EK(int s,int t)
{
int v,w,d,maxflow=0;
while(bfs(s,t))
{
v=t;
d=inf;
while(v!=s)
{
w=pre[v];
d=min(d,g[w][v]);
v=w;
}
maxflow+=d;
v=t;
while(v!=s)
{
w=pre[v];
g[w][v]-=d;
g[v][w]+=d;
if(f[v][w]>0)
f[v][w]-=d;
else
f[w][v]+=d;
v=w;
}
}
return maxflow;
}
int main()
{
int a,b,c;
while(~scanf("%d%d",&m,&n))
{
mem(g,0);
mem(f,0);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
g[a][b]+=c;
}
printf("%d\n",EK(1,n));
}
return 0;
}
取消实流网络f以后:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
const int N=200+20;
int g[N][N],pre[N];//分别代表残余网络,前驱数组
bool vis[N];//标记数组
int n,m;//点数和边数
bool bfs(int s,int t)
{
mem(pre,-1);
mem(vis,false);
queue<int>q;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=1; i<=n; i++)
{
if(!vis[i]&&g[now][i]>0)
{
vis[i]=true;
pre[i]=now;
if(i==t)
return true;
q.push(i);
}
}
}
return false;
}
int EK(int s,int t)
{
int v,w,d,maxflow=0;
while(bfs(s,t))
{
v=t;
d=inf;
while(v!=s)
{
w=pre[v];
d=min(d,g[w][v]);
v=w;
}
maxflow+=d;
v=t;
while(v!=s)
{
w=pre[v];
g[w][v]-=d;
g[v][w]+=d;
v=w;
}
}
return maxflow;
}
int main()
{
int a,b,c;
while(~scanf("%d%d",&m,&n))
{
mem(g,0);
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a,&b,&c);
g[a][b]+=c;
}
printf("%d\n",EK(1,n));
}
return 0;
}