Time Limit: 2000MS | Memory Limit: 32768K | |
Total Submissions: 27505 | Accepted: 14294 |
Description
Input
Output
Sample Input
2 1 1 2 (0,1)20 (1,0)10 (0)15 (1)20 7 2 3 13 (0,0)1 (0,1)2 (0,2)5 (1,0)1 (1,2)8 (2,3)1 (2,4)7 (3,5)2 (3,6)5 (4,2)7 (4,3)5 (4,5)1 (6,0)5 (0)5 (1)2 (3)2 (4)1 (5)4
Sample Output
15 6
Hint
题意:
给定一系列发电站,消费者,传送站,以及相应的发电量,消费量,传送量
求解这些站点中最大消费的电量可以是多少
题解:
运用网络流来求解,因此需要建立一个源点n+1和一个汇点n+2来构建图
一般预留推进算法思想:
选择活跃顶点,通过它把一定的流量推进到它的邻接顶点,尽可能把每个点的余流减少为0
算法基本框架:
第一步:初始化源点余流为无穷大,源点距离标号为n
第二步:从当前点出发,寻找活跃顶点,如果没有就结束程序
第三步:如果到达汇点就把所推进的流加入的需求的答案中
第四步:选取的活跃顶点中,如果有允许弧,则推进min(RE,EF)流
第五步:推进完后判断当前的点是不是活跃顶点
第六步:转第二步
#include
#include
#include
#include
using namespace std;
#define MAXN 110
#define INF 0x3f3f3f
int n,np,nc,m;
int s,t;//源点 汇点
int RE[MAXN][MAXN];//残留网络
queueque;
int H[MAXN];//高度
int EF[MAXN];//余流
int maxFlow;
void init()
{
memset(RE,0,sizeof(RE));
memset(H,0,sizeof(H));
memset(EF,0,sizeof(EF));
maxFlow=0;
s=n+1,t=n+2;
EF[s]=INF;
EF[t]=-INF;
H[s]=n;
}
void Push(int cur)
{
for(int i=1;i<=t;i++){
int temp=min(RE[cur][i],EF[cur]);
if(temp>0&&(cur==s||H[cur]-H[i]==1)){
//存在允许弧
RE[cur][i]-=temp;
RE[i][cur]+=temp;
EF[cur]-=temp;
EF[i]+=temp;
if(i==t)
maxFlow+=temp;
else if(i!=s)
que.push(i);
}
}
}
void Relabel(int cur)
{
if(cur!=s&&cur!=t&&EF[cur]>0){
H[cur]++;
que.push(cur);
}
}
void push_relabel()
{
int cur;
que.push(s);
while(!que.empty()){
cur = que.front();
que.pop();
Push(cur);
//推进之后判断cur点是不是活跃顶点
Relabel(cur);
}
printf("%d\n",maxFlow);
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
{
init();
char ch;
int u, v, val;
for(int i=0;i