[USACO4.2] 草地排水Drainage Ditches
题目背景
在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水。这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间。因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没的烦恼(不用担心,雨水会流向附近的一条小溪)。作为一名一流的技师,农夫约翰已经在每条排水沟的一端安上了控制器,这样他可以控制流入排水沟的水流量。
题目描述
农夫约翰知道每一条排水沟每分钟可以流过的水量,和排水系统的准确布局(起点为水潭而终点为小溪的一张网)。需要注意的是,有些时候从一处到另一处不只有一条排水沟。
根据这些信息,计算从水潭排水到小溪的最大流量。对于给出的每条排水沟,雨水只能沿着一个方向流动,注意可能会出现雨水环形流动的情形。
输入格式
第一行:两个用空格分开的整数 N N N( 0 ≤ N ≤ 200 0 \le N \le 200 0≤N≤200)和 M M M( 2 ≤ M ≤ 200 2 \le M \le 200 2≤M≤200)。 N N N 是农夫 John 已经挖好的排水沟的数量, M M M 是排水沟交叉点的数量。交点 1 1 1 是水潭,交点 M M M 是小溪。
第二行到第 N + 1 N + 1 N+1 行:每行有三个整数, S i , E i , C i S_i, E_i, C_i Si,Ei,Ci。 S i S_i Si 和 E i E_i Ei( 1 ≤ S i , E i ≤ M 1 \le S_i, E_i \le M 1≤Si,Ei≤M)指明排水沟两端的交点,雨水从 S i S_i Si 流向 E i E_i Ei。 C i C_i Ci( 0 ≤ C i ≤ 10 7 0 \le C_i \le {10}^7 0≤Ci≤107)是这条排水沟的最大容量。
输出格式
输出一个整数,即排水的最大流量。
样例 #1
样例输入 #1
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
样例输出 #1
50
提示
题目翻译来自NOCOW。
USACO Training Section 4.2
【数据范围】
对于 100 % 100 \% 100% 的数据, 0 ≤ N , M ≤ 200 0 \le N, M \le 200 0≤N,M≤200, 0 ≤ C i ≤ 10 7 0 \le C_i \le {10}^7 0≤Ci≤107。
思路
就是最大流问题,只不过源点和汇点分别是1和m。
代码
//最大流+EK算法
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N = 210,M = 2*N,INT = 2e9;
int f[M],h[N],ne[M],e[M],idx;
bool st[N];
int d[N];//表示每个节点到源点的最短费用
int n,m,S,T;
int pre[N];
void add(int a,int b,int c){
e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}
bool bfs(){
queue<int>q;
memset(st,0,sizeof st);
q.push(S);
st[S]=true;
d[S]=INT;
while(q.size()){
int t=q.front();
q.pop();
for(int i=h[t];~i;i=ne[i]){
int ver=e[i];
if(!st[ver]&&f[i]){
st[ver]=true;
d[ver]=min(d[t],f[i]);
pre[ver]=i;
if(ver==T)return true;
q.push(ver);
}
}
}
return false;
}
int EK(){
int r=0;
while(bfs()){
r+=d[T];
for(int i=T;i!=S;i=e[pre[i]^1]){
f[pre[i]]-=d[T];
f[pre[i]^1]+=d[T];
}
}
return r;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
S=1,T=m;
cout<<EK();
return 0;
}