问题描述:约翰是个农民,每次下雨的时候他的庄家总是会被淹没,这就意味着当庄家被水淹后需要很长时间才能重新生长出来,因此,约翰已经建立了一系列排水管道为了使他的庄家尽可能被淹没的最少,也就是说管道的排水量必须很大.作为一名工程师,约翰可以计算出管道网能排水的最大能力.
Input:输入包含多组用例,每组用例第一行是两个数N,M,N表示一共有N个管道,M表示一共有M个点,接下来N行每行输入三个数字a,b,c表示,a管道口到b管道口最大排水能力为c.
Output:对每一组用例,输出排水量的最大值
Sample Input:
5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
Sample Output:
50
这里我采用的是Fold-Fulkerson算法。
//这里的起点默认为1,终点为节点数M
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<string.h>
#define maxint 999999999
using namespace std;
int rest[500][500];//二位数组rest绘制有向图
int pre[500];//保存每次需找的增广路径的前驱
int Min;//写法原因Min需定义为全局变量
bool bfs(int M)//增广路径的搜索
{
queue<int>que;
bool vis[500];//常规搜索都有的标记数组vis;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));//前驱数组初始化
que.push(1);
vis[1]=1;
while(!que.empty())
{
int s=que.front();
que.pop();
if(s==M)
{
return true;
}
for(int i=1;i<=M;i++)
{
if(rest[s][i]&&vis[i]==0)//rest[s][t]不为0说明选择的这条路径中从s点到达i点的通道还未被充满,说明当前存在增广路径
{
pre[i]=s;//前驱数组更新
vis[i]=1;
que.push(i);
}
}
}
return false;//若不存在增广路径则返回false说明找不到
}
void update(int M)//对每次所选的路径可增加流量更新,返回并加到总流量数sum中
{
if(M==1)//从后往前找起,知道找到起点为止
return;
int s=pre[M];
Min=min(Min,rest[s][M]);
update(s);//回溯更新
rest[s][M]-=Min;//正反路径进行更新的区别
rest[M][s]+=Min;
}
int main()
{
int a,b,c;
int N,M;
while(scanf("%d%d",&N,&M)!=EOF)
{
memset(rest,0,sizeof(rest));
for(int i=1;i<=N;i++)
{
scanf("%d%d%d",&a,&b,&c);
rest[a][b]+=c;//想清楚为什么是+不是=
}
int sum=0;
while(bfs(M))
{
Min=maxint;//由于可能有多次路径选择所以需要在while内对全局变量Min进行更新
update(M);
sum+=Min;
}
printf("%d\n",sum);//输出到达终点可达到的最大流量
}return 0;
}