POJ 1459 Power Network (最大流, 网络流, EdmondsKarp算法求解最大流)

题意:  给定np个发电站, nc个消费者, m条从u流到v的边, 其权值为边的最大容量, 求解, 消费者总的最大可用电量

求解:  增加两个点:源点以及汇点,  源点指向所有的发电站(即给发电站提供电量, 但是每个发电站最大接收量已被限制), 所有的消费者指向汇点(即消费者所能用的电量全部汇聚到该汇点上,每个消费者能用的电量有最大限制), 构建网络流模型, 用EdmondsKarp算法求解

code:

/*
   s(u)  u被提供的能量数
   p(u)  0<=p(u)<=Pmax(u) u产生的能量数
   c(u)  u消耗的能量数  (0<=c(u)<=minn(s(u), Cmax(u)))
   d(u)  u向外传递的能量数 = s(u)+p(u)-c(u)
   每个发电站         c(u) = 0;
   每个消费者(用电者)  p(u)=0;
   每个调度员   c(u)=0 && p(u)=0;
   u到v至多一条电力通路
   l(u, v) u传送到v的总能量数
   Con = EuC(u), 消耗总和
   求Con最大值
 */
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 205;
const int inf = 0x3f3f3f3f3f;
int n, np, nc, m, s, e;//s->源点,  e->汇点
//n:nodes
//np: power stations 发电站数
//nc: consumers  消费者数
//m: 电力通路数
int edge[maxn][maxn];// u-v之间电力通路传送最大值
int flow[maxn], vis[maxn];
int pre[maxn];
//找出所有增广路, 每找出一条就在各个边上去掉汇点上所获得的能量
int bfs(){
	int i, v;
	queue<int>que;
	memset(flow, -1, sizeof(flow));
	memset(vis, 0, sizeof(vis));
	while(!que.empty()) que.pop();
	que.push(s);
	vis[s] = 1;
	flow[s] = inf;
	pre[s] = s;
	while(!que.empty()){
		v = que.front();
		que.pop();
		for(i=s; i<=e; i++){
			if(vis[i]&&edge[v][i]){
				vis[i] = 1;
				flow[i] = min(flow[v], edge[v][i]);
				que.push(i);
				pre[i] = v;
			}
		}
	}
	if(flow[e]!=-1){
		return flow[e];
	} else {
		return 0;
	}
}
int EdmondsKarp(){
	int i, MIN;
	int maxflow = 0;
	while(MIN=bfs()){
		for(i=e; i!=s; i=pre[i]){
			edge[pre[i]][i] -= MIN;//正向边
			edge[i][pre[i]] += MIN;//反向边
		}
		maxflow += MIN;
	}
	return maxflow;
}
int main()
{
	int i, j, k;
	char c;
	while(~scanf("%d %d %d %d%*c", &n, &np, &nc, &m)){
		s=0, e=n+1;
		memset(edge, 0, sizeof(edge));
		int x, y, z;
		for(i=1; i<=m; i++){
			while((c=getchar())!='(');
			scanf("%d,%d)%d", &x, &y, &z);
			if(x==y) continue;
			edge[x+1][y+1]+=z;
		}
		for(i=1; i<=np; i++){
			while((c=getchar())!='(');
			scanf("%d)%d", &x, &z);
			edge[s][x+1] = z;//源点与每个发电站建立联系
		}
		for(i=1; i<=nc; i++){
			while((c=getchar())!='(');
			scanf("%d)%d", &x, &z);
			edge[x+1][e] = z;//汇点与每个消费者建立联系
		}
		printf("%d\n", EdmondsKarp());
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值