POJ 1273 Drainage Ditches 我的第一道网络流——最大流问题

题目大意就不说了是一道裸的网络流中的最大流问题,可以用增广路算法来做,即EDMONDS-KARP算法。 读入会有多组数据,每一组先有N和M,N表示图中边的条数,M表示图中节点的个数,接下来有N行数据,每行有三个数 S ,E, C 表示一条边的起点,终点和边上的容量,注意是有向边,而且有重边;

好了题目就是这样,还是说一下这个算法吧,这个算法其实是很暴力的。。他每次只是用BFS找到一条路,使得在这条路上的每一条边的残流量(****即容量与流量(**流量就是实际使用的容量有正负的,如果从A到B 的流量是c,那么从B到A的流量就是-c因为方向相反嘛,是吧?**)之差******)都大于0(*******其中残流量就是经过使用后这条边上还剩余的可使用流量,是有向的,比如从v到u的容量是c,从u到v的容量是零,从v到u的流量是F,那么从u到v的流量就是-F,于是从v到u的残流量就是c-F,从u到v的残流量就是0-(-F)=F(************这个残流量实际是会变大的,是吧?因为本来不能把东西从U运到V的但是,你把东西从v运到u后,我就可以等效的认为可以把东西从u运到v了,为什么?想一想其实很简单,因为假设你想把5个东西从v往u运,而实际上你只运了2个,那我就可以这样说,你从v往u运了5个东西而我从u往v运了3个东西,这样结果是不是等价的????是吧,这就是残流量的神奇了***********)。  这些概念一定要龙清楚而且要知道怎么算*****)

啊,注释好像略多额,好吧继续说那个,找到了一条残流量都大于0的路径。这说明了什么呢?这条路?那就是这条路上可以运送东西?那可以运送多少东西呢?当然是这条路上的最小的残留量啊,是吧?想想其实很简单,如果不是最小的,那你把东西运到最小的残流量的那条边上的时候,他肯定就运不过去啊。

这样也知道运多少了,那就运呗,运的时候就更新一下整条路上的流量就行,注意正反的流量都需要更新。

然后就重复这个找路得过程就行了。直到找不到整条路的最小残流量都大于0路径,那么算法就结束了

/*********
PRO: POJ 1273
TIT: Drainage Ditches
DAT: 2013-08-12
AUT: UKean
EMA: huyocan@163.com
ALG: Edmonds_Karp
*********/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define  INF 1e9
using namespace std;
queue<int> que;//广搜需要使用的队列
int N,M;//N是边数,M是点数
int s,t;//源点和汇点
int flow[205][205];//流量
int p[205];//广搜记录路径的父节点数组
int a[205];//路径上的最小残流量
int cap[205][205];//容量网络
int ans;
int read()
{
	memset(cap,0,sizeof(cap));
	for(int i=0;i<N;i++)
	{
		int sta,en,ca;
		cin>>sta>>en>>ca;
		cap[sta][en]+=ca;//这样就可以处理重边了
	}
	s=1;t=M;//s是源点,t是汇点
	return 1;
}

void deal()//最大流算法
{
	memset(flow,0,sizeof(flow));//初始化流量
	ans=0;//最大流
	while(1)
	{
		memset(a,0,sizeof(a));
		a[s]=INF;
		que.push(s);
		while(!que.empty())//广搜找到增广路,就是那个最小的残流量大于零的路径
		{
			int u=que.front();que.pop();
			for(int v=1;v<=M;v++)
			if(!a[v]&&cap[u][v]-flow[u][v]>0)//cap[u][v]-flow[u][v] 表示残流量,
			//扩张新的的节点!a[v]确保该节点没被访问过,残流量大于0确保找的的路径符合要求
			{
				p[v]=u;//用来记录v的父亲,保存路径
				que.push(v);//入队
				a[v]=min(a[u],cap[u][v]-flow[u][v]);//记录路径上的最小残流量
			}
		}
		if(a[t]==0) break;//如果找不到路径最小残流量大于0的路径了就结束算法
		for(int u=t;u!=s;u=p[u])//迭代找回路径修改,路径上的流量
		{
			flow[p[u]][u]+=a[t];//更新正向的流量
			flow[u][p[u]]-=a[t];//更新方向流量
		}
		ans+=a[t];//增加最大流
	}
	cout<<ans<<endl;
}
int main()
{
	while(cin>>N>>M)
	{
		read();
		deal();
	}
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值