[POJ 1273]Drainage Ditches——网络流最大流入门

Drainage Ditches
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 70902 Accepted: 27570

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

Source

USACO 93


题目大意:在一片草地中有一个池塘,要排掉里面的水到另一个池塘,它们间有许多分叉的小溪相连,每个小溪同时只能通过一定量的水,问同时能排掉的最多的水是多少

题目分析:裸的网络流最大流。。。

网络流de介绍:


手绘别介意。。。

那么,网络流是这样的一些东西:
如上图,要把很多水从S起点排到T终点,它们中间有一些管道和中转站,每条管道都有一个最大的流量(就像八车道的“八”,是同时走八辆车一样)。。。
这就是网络流。。。

这道题是网络流中的最大流:
还是上图,问每次最多能有多少水被同时排掉(只发一次车可以允许几辆车到)?
答案很显然:



上图中,水1的大小是4,水2的大小是4,水3的大小是2。。。

显然只要数据不大,肉眼很容易完成这道题。。。

但如何用程序实现呢?

这就需要我们运用一个神奇的方法,叫做寻找增广路:
以水1作为例子:
首先广搜,若找到的第一个目标是水1,

如果只是单纯的减去:
显然这样瞎搞是不对的。。。
正确的做法如图:
首先,找到这条路上最小的流量:

然后,对每一条经过的边减去该最小流量。。。

这样:

然后, 添加反向边,大小为刚才最小值的大小(疑问稍后)

并将刚才的最小值加入答案中,完成!
如此反复的执行上面的“寻找增广路”直到找不到,输出答案即可;

为什么要加反向边呢?

还记得一个神奇的算法叫做——DFS吗?

DFS的作用机制是:枚举每一种情况,若当前情况不可行,则 后悔当前操作并继续枚举下一种。。。

人非圣贤,孰能无过。。。 程序同理。。。

如果程序在找增广路时,当前不是最优,难道连后悔的机会都不给吗?那岂不找不到最优?

但,怎么给程序后悔的机会??显然不可能是DFS。。。

这就是 反向边存在的意义:给程序后悔的机会!

这些神奇的反向边的增加,相当于把刚才用掉的流量又“退”了回去,也就是 后悔掉操作。。。

在本题中。。。额。。本题就是网络流模板。。。看题意应该看得出来。。。

那么就是代码了:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<queue>
#define Inf 999999999

using namespace std;

int n,m;
int map[300][300];
bool vis[300];
int fa[300];

unsigned bfs(){
        //BFS开始
	queue<int> q;
	memset(fa,0,sizeof(fa));
	memset(vis,0,sizeof(vis));
	
	fa[1]=0;
	vis[1]=1;
	q.push(1);
	bool flag=false;
	int tmp;
	
	while(!q.empty()){
		tmp=q.front();
		q.pop();
		
		for(int i=1;i<=m;i++){
			if(map[tmp][i]>0 && vis[i]==0){//注意,当前找到的边剩余流量必须大于零(map[][]>0)
				fa[i]=tmp;//记录来路
				vis[i]=1;//往下找
				if(i==m){//找到终点跳出,即找到了一条增广路
				    flag=true;//有发现
				    break;
				}
				else
					q.push(i);
			}
		}
	}
	
	if(!flag){//如果什么发现也没有
		return 0;
	}
	
	int Min=Inf;//最小值
	tmp=m;
	
	while(fa[tmp]){//沿来路找最小值
		Min=Min<map[fa[tmp]][tmp]?Min:map[fa[tmp]][tmp];
		tmp=fa[tmp];
	}
	
	tmp=m;
	
	while(fa[tmp]){//沿来路建反向边并减去最小值
		map[fa[tmp]][tmp]-=Min;
		map[tmp][fa[tmp]]+=Min;
		tmp=fa[tmp];
	}
	
	return Min;//返回最小流量
}

int main(){
	int a,b,c;
	while(scanf("%d%d",&n,&m)!=EOF){
		
		memset(map,0,sizeof(map));//清空图
		
		for(int i=1;i<=n;i++){
			scanf("%d%d%d",&a,&b,&c);
			map[a][b]+=c;//邻接矩阵
		}
		
		unsigned int ans=0;
		unsigned int tmp;
		
		while(tmp=bfs()){//BFS就是寻找增广路,见上方
			ans+=tmp;
		}
		
		printf("%u\n",ans);
		
	}
	return 0;
}
其实就是个普通的广搜+2while循环而已。。。

注释:(为了显得正规一点)
找过增广路后的剩余图叫“残余网络”
起点叫“原点”
终点叫“汇点”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值