POJ 1459 Power Network

题目大意:

        一电力网包含若干结点,结点间最多连有一条电力线,对于某个结点u可以有以下参数:

                s(u) 电力供应量

                p(u) 电力生产量

                c(u) 电力消耗量

                对于发电站c(u) = 0,对于消费者p(u) = 0,对于中继站c(u) = p(u) = 0,对于每条输电线路都有一个最大容量(即最大流量),输电线路是单向的。

        现求这个网络的最大电力消耗量可以达到多少,有多个测例(测例数无上限),每个测例中给出总结点数、发电站数、消费者数、电力输送线条数,非别对应变量n、np、nc、m(0 ≤ n, np, nc ≤ 100, 0 ≤ m ≤ n ^ 2),其中传输线的容量不超过1,000,发电站和消费者的容量不超过10,000,接下来会给出每条线路的起点和终点以及流量上限、各发电站的编号和输出上限、各消费者的编号和消费上限,对于每个测例都输出该网络的最大消费量。

题目链接

注释代码:

/*                      
 * Problem ID : POJ 1459 Power Network 
 * Author     : Lirx.t.Una                      
 * Language   : G++          
 * Run Time   : 500 ms                      
 * Run Memory : 720 KB                      
*/ 

#pragma G++ optimize("O2")

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

//流量的上限(最大为100,000)
#define	INF				100001

//maximum number of nodes
//电力网中结点的最大数量
//结点编号从0开始,最多为101个
//再加上网络流中的源点和汇点
//下标应到102,因此最大数取103
#define	MAXNODEN		103
//maximum length of format string
//格式字符串的最大长度
//用来暂时存储输入的数据
//不能直接用scanf格式读取连续字符串中的
  //数字数据
#define	MAXFMTSLEN		30

#define	MIN(x,y)		( (x) < (y) ? (x) : (y) )

using namespace std;

//flow,网络流,精确地说是残余网络
//flw[u][v]表示从结点u到结点v的当前可用流量
//即当前流量余额
int		flw[MAXNODEN][MAXNODEN];
//previous node
//pre[u]表示寻找到的增广路路径中u结点的前驱结点的编号
char	pre[MAXNODEN];

char	sfmt[MAXFMTSLEN];

bool
bfs( int src, int des ) {//广度搜索寻找到第一条可行增广路径
	//source node and destination,源点和汇点

	queue<int>		que;//临时队列

	int		u, v;//前驱和后继结点的编号

	//由于有0号结点,因此增光路径前驱都初始化为-1
	memset(pre, -1, ( des + 1 ) * sizeof(char));

	que.push(src);//先将源结点入队
	
	while ( !que.empty() ) {
	
		u = que.front();
		que.pop();

		for ( v = 0; v <= des; v++ )
			if ( -1 == pre[v] && flw[u][v] ) {//寻找可行流
				//即无直接前驱同时又有流量的(即存在路径的)
			
				pre[v] = u;//衔接
				if ( v == des )//若已经搜索到了汇点则直接成功退出
					return true;

				que.push(v);
			}
	}

	return false;//没有搜索到,则表示增广路径已经不存在了,则失败退出
}

//算法的大致过程:
//每求出一条增广路就计算一次当前网络的残余网络
//若能在残余网络中再能找出增光路就说明还有可行流
//不停累加可行流并更新残余网络,直到残余网络中不存在增广路径为止
  //此时就说明已经没有可行流了
int
maxflw( int src, int des ) {//maximum flow,求取最大流

	int		ans;
	int		u, v;
	int		minf;//minimum flow,每条增光路径中的最小的边,即最小流
	        //因为一条增光路径的流量是由剩余流量最小的那条流决定的

	ans  = 0;
	while ( bfs( src, des ) ) {//先在残余网络中搜索出一条增广路

		for ( minf = INF, v = des, u = pre[des]; v != src; v = u, u = pre[v] )
			minf = MIN( minf, flw[u][v] );//找出此增广路中的最小流

		for ( v = des, u = pre[des]; v != src; v = u, u = pre[v] ) {
		
			flw[u][v] -= minf;//将此增广路中的前向弧减去消耗的流量
			flw[v][u] += minf;//反向弧增加消耗的流量(类似向量的运算)
		}

		ans += minf;//每一条可行增广路径的可行流进行累加
	}

	return ans;
}

int
main() {

	int		n, np, nc, m;//结点总数、发电站、消费者、弧数
	int		u, v, f;
	int		src, des;
	int		i;

	while ( ~scanf("%d%d%d%d", &n, &np, &nc, &m) ) {
	
		src = n;
		des = n + 1;

		for ( i = 0; i <= des; i++ )	
			memset(flw[i], 0, ( des + 1 ) * sizeof(int));

		while ( m-- ) {
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d,%d)%d", &u, &v, &f);
			flw[u][v] = f;
		}

		while ( np-- ) {//发电站的流量来自源点
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d)%d", &v, &f);
			flw[src][v] = f;
		}

		while ( nc-- ) {//消费者的消耗量流向汇点
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d)%d", &u, &f);
			flw[u][des] = f;
		}

		printf("%d\n", maxflw( src, des ));
	}

	return 0;
}

无注释代码:

#pragma G++ optimize("O2")

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>

#define	INF				100001

#define	MAXNODEN		103
#define	MAXFMTSLEN		30

#define	MIN(x,y)		( (x) < (y) ? (x) : (y) )

using namespace std;

int		flw[MAXNODEN][MAXNODEN];
char	pre[MAXNODEN];

char	sfmt[MAXFMTSLEN];

bool
bfs( int src, int des ) {

	queue<int>		que;

	int		u, v;

	memset(pre, -1, ( des + 1 ) * sizeof(char));

	que.push(src);
	
	while ( !que.empty() ) {
	
		u = que.front();
		que.pop();

		for ( v = 0; v <= des; v++ )
			if ( -1 == pre[v] && flw[u][v] ) {
			
				pre[v] = u;
				if ( v == des )
					return true;

				que.push(v);
			}
	}

	return false;
}

int
maxflw( int src, int des ) {

	int		ans;
	int		u, v;
	int		minf;

	ans  = 0;
	while ( bfs( src, des ) ) {

		for ( minf = INF, v = des, u = pre[des]; v != src; v = u, u = pre[v] )
			minf = MIN( minf, flw[u][v] );

		for ( v = des, u = pre[des]; v != src; v = u, u = pre[v] ) {
		
			flw[u][v] -= minf;
			flw[v][u] += minf;
		}

		ans += minf;
	}

	return ans;
}

int
main() {

	int		n, np, nc, m;
	int		u, v, f;
	int		src, des;
	int		i;

	while ( ~scanf("%d%d%d%d", &n, &np, &nc, &m) ) {
	
		src = n;
		des = n + 1;

		for ( i = 0; i <= des; i++ )	
			memset(flw[i], 0, ( des + 1 ) * sizeof(int));

		while ( m-- ) {
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d,%d)%d", &u, &v, &f);
			flw[u][v] = f;
		}

		while ( np-- ) {
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d)%d", &v, &f);
			flw[src][v] = f;
		}

		while ( nc-- ) {
		
			scanf("%s", &sfmt);
			sscanf(sfmt, "(%d)%d", &u, &f);
			flw[u][des] = f;
		}

		printf("%d\n", maxflw( src, des ));
	}

	return 0;
}

单词解释:

 power station:n, 发电站

consumer:n, 消费者,顾客,客户

dispatcher:n, 调度员,调度程序

supply with:提供...

be supplied with:被提供给...

consume:vt, 消费,消耗

deliver:vt, 递送,释放(能量)

restriction:n, 限制,约束,约束条件

triplet:n, 三元组,三连音

integral:adj, 整数的,积分的,完整的
doublet:n, 二元组,成对物

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值