题目大意:
一电力网包含若干结点,结点间最多连有一条电力线,对于某个结点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, 二元组,成对物