问题描述
每当约翰的田里下雨,贝西最喜欢的三叶草地里就会形成一个池塘。这意味着三叶草被水覆盖了一段时间,需要很长时间才能重新生长。因此,农夫约翰建了一套排水沟,这样贝西的苜蓿地就不会被水覆盖了。相反,水被排到附近的小溪。作为一名一流的工程师,农夫约翰还在每条水沟的开头安装了调节器,这样他就能控制水流进水沟的速度。
农夫约翰不仅知道每分钟每条沟渠能输送多少加仑的水,还知道沟渠的精确布局,这些沟渠从池塘里流出,相互流入,形成一个潜在的复杂网络。
根据所有这些信息,确定水从池塘中进入小溪的最大速度。对于任何给定的沟渠,水只朝一个方向流动,但可能有一种方式可以让水在一个圆圈中流动。
输入
输入包括几种情况。对于每种情况,第一行包含两个空格分隔的整数,N (0 <= N <= 200)和M (2 <= M <= 200)。N是农民约翰挖的沟的数目。M是这些沟渠的交叉点个数。交叉口1是池塘。交点M是流。下面N行中的每一行都包含三个整数,Si、Ei和Ci。Si和Ei (1 <= Si, Ei <= M)表示该沟渠流经的交叉口。水将通过这条沟从Si流到Ei。Ci (0 <= Ci <= 10,000,000)是水流通过沟渠的最大速度。
输出
对于每种情况,输出一个整数,即从池塘中排空水的最大速度。
Sample Input
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output
50
分析:
裸题,不多bb。
代码自带少许注释
code(EK算法):
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<algorithm>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=205;
int n,m;
int g[maxm][maxm];
int pre[maxm];
int mark[maxm];
int bfs(int s,int t){//bfs一遍标记反向路径
memset(mark,0,sizeof mark);
memset(pre,0,sizeof pre);
pre[s]=s;
mark[s]=1;
queue<int>q;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=1;i<=n;i++){
if(!mark[i]&&g[x][i]){//如果没标记过(即没走过)且容量不为0(容量为0表示没有路)
pre[i]=x;
mark[i]=1;
if(i==t)return 1;
q.push(i);
}
}
}
return 0;
}
int ek(int s,int t){
int ans=0;//最大流
while(bfs(s,t)){
int d=inf;
for(int i=t;i!=s;i=pre[i]){//找最小detla
if(g[pre[i]][i]<d){
d=g[pre[i]][i];
}
}
for(int i=t;i!=s;i=pre[i]){
g[pre[i]][i]-=d;//正边减少
g[i][pre[i]]+=d;//反边增加
}
ans+=d;
}
return ans;
}
int main(){
while(cin>>m>>n){//个人习惯把n作为节点数量,m作为路径数量,和这题题目是反的
memset(g,0,sizeof g);//容量为0表示没有路
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
g[a][b]+=c;//重边合并成一条边
}
cout<<ek(1,n)<<endl;
}
return 0;
}