poj 1459 Power Network 网络流初步,增广路算法,主要是建图麻烦

题意是一个实际问题, 电网 。原题的描述感觉不太好懂而且一些公式也是扯淡。  整个电网中有 :电站 可以发电 ,用户 可以使用电,还有中继站 可以传送电能 ,当然也有电线,电线的输送电能的能力有方向,不同方向的能力可能不同。当然啦也可能有重边。题目问的是从发电站发出的电最多可以给用户使用多少。一般的网络流的题目都有唯一的源点和汇点,但是此题的唯一源点和汇点并没有给出,需要我们自己来建,我们建的这种源点和汇点也称为超级源点和超级汇点,因为本题中的每个发电站都是源点,而每个用户都是都是汇点,这样这个问题的源点和汇点就有很多了,我们不可能根据每个源点和汇点都做一次增广路算法,所以就有了超级源点和超级汇点,即让超级源点和每个源点建立一条边,这样原来的源点就变成了普通点不再是源点,亦可以对多个汇点进行同样的处理产生一个超级的汇点。那么题目就简单了

再说一下题目的读入

多组数据,每组先是有四个数据 N,np,nc,M 其中N表示节点数(包括用电用户,中继站,发电站的总数)np表示发电站的个数,nc表示,用电户的个数,M表示电线的个数

然后再输出M组数据表示电线,每根电线用(u,v)z表示表示从u到v最多可以传送的电量为z

再输出np个发电站,每个发电站形式是(u)z表示发电站u可以发电最多z

最后输出nc个用电户,每个用电户的形式是(u)z,表示用电户u最多会用z的电

好的题目就说这么多了

具体的见代码注释

/*********
PRO: POJ 1459
TIT: Power Network
DAT: 2013-08-12
AUT: UKean
EMA: huyocan@163.com
*********/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define  INF 1e9
using namespace std;
queue<int> que;//广搜需要使用的队列
int M,N;//M是边数,N是点数
int s,t;//源点和汇点
int flow[1005][1005];//流量
int p[1005];//广搜记录路径的父节点数组
int a[1005];//路径上的最小残量
int cap[1005][1005];//容量网络
int ans;//最大流
int read()//读入数据建图
{
	int np,nc,u,v,z;
	if(!(~scanf("%d%d%d%d",&N,&np,&nc,&M))) return 0;
	s=N+1;t=N+2;//超级源点,超级汇点
	memset(cap,0,sizeof(cap));//初始化容量网络
	for(int i=0;i<M;i++)//读入电线
	{
		scanf(" (%d,%d)%d",&u,&v,&z);
		cap[u][v]+=z;//为了防止重边所以累加容量
	}
	for(int i=0;i<np;i++)
	{
		scanf(" (%d)%d",&u,&z);
		cap[s][u]+=z;//读入发电站,和超级源点建立一条边
	}
	for(int i=0;i<nc;i++)
	{
		scanf(" (%d)%d",&u,&z);
		cap[u][t]+=z;//度入用户和超级汇点建立一条边
	}
	return 1;
}

int deal()//增广路算法就不具体解释了,详细的解释可以看我关于网络流的第一篇博客
//http://blog.csdn.net/hikean/article/details/9918093
{
	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=0;v<=N+2;v++)
			if(!a[v]&&cap[u][v]-flow[u][v]>0)
			{
				p[v]=u;
				que.push(v);
				a[v]=min(a[u],cap[u][v]-flow[u][v]);//路径上的最小残流量
			}
		}
		if(a[t]==0) break;
		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;
	return ans;
}
int main()
{
	while(read())
		deal();
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值