poj 1459 多源多汇最大流模板题 Dinic

Power Network
Time Limit: 2000MS   Memory Limit: 32768K
Total Submissions: 29855   Accepted: 15447

Description

A power network consists of nodes (power stations, consumers and dispatchers) connected by power transport lines. A node u may be supplied with an amount s(u) >= 0 of power, may produce an amount 0 <= p(u) <= p max(u) of power, may consume an amount 0 <= c(u) <= min(s(u),c max(u)) of power, and may deliver an amount d(u)=s(u)+p(u)-c(u) of power. The following restrictions apply: c(u)=0 for any power station, p(u)=0 for any consumer, and p(u)=c(u)=0 for any dispatcher. There is at most one power transport line (u,v) from a node u to a node v in the net; it transports an amount 0 <= l(u,v) <= l max(u,v) of power delivered by u to v. Let Con=Σ uc(u) be the power consumed in the net. The problem is to compute the maximum value of Con.

An example is in figure 1. The label x/y of power station u shows that p(u)=x and p max(u)=y. The label x/y of consumer u shows that c(u)=x and c max(u)=y. The label x/y of power transport line (u,v) shows that l(u,v)=x and l max(u,v)=y. The power consumed is Con=6. Notice that there are other possible states of the network but the value of Con cannot exceed 6.

Input

There are several data sets in the input. Each data set encodes a power network. It starts with four integers: 0 <= n <= 100 (nodes), 0 <= np <= n (power stations), 0 <= nc <= n (consumers), and 0 <= m <= n^2 (power transport lines). Follow m data triplets (u,v)z, where u and v are node identifiers (starting from 0) and 0 <= z <= 1000 is the value of l max(u,v). Follow np doublets (u)z, where u is the identifier of a power station and 0 <= z <= 10000 is the value of p max(u). The data set ends with nc doublets (u)z, where u is the identifier of a consumer and 0 <= z <= 10000 is the value of c max(u). All input numbers are integers. Except the (u,v)z triplets and the (u)z doublets, which do not contain white spaces, white spaces can occur freely in input. Input data terminate with an end of file and are correct.

Output

For each data set from the input, the program prints on the standard output the maximum amount of power that can be consumed in the corresponding network. Each result has an integral value and is printed from the beginning of a separate line.

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

题意: 给你n个点m条有向边,有np个电站,nc个用户,每一个电站都可以提供有限的电能,每个用户都有一定对电的需求,每条边都有最大的流通电流的容量,问这nc个用户最多可以获得多少的电能。

思路: 多源多汇最大流模板题,构造一个超级源点,超源指向所有的源点,正向容量为该电站可以提供的电能,反向随意(因为广搜的dep标记是不会让他往超源走的),所有的汇点指向一个超级汇点,边的容量为原汇点所需的容量,然后直接Dinic(详情请看我上一篇博客)。注意的是,以前我还没注意优化,直到T了无数次后才发现在dfs的时候还可以继续大大的优化,以往是每个dfs只找一条可行流,优化后就是每个点所有可行流都访问并结合大大节约了时间,具体看代码。

注意: 本题有点坑,那就是输入的时候需要输入括号和逗号,如果简单只用%c会出大问题,所以有很多种解决的办法,详情看代码。

代码
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue> 
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
struct Edge{
	int to,cap,rev;
};
vector<Edge>v[205];//101 为超级源点 102为超级汇点 
int dep[205],iter[205];
int n,np,nc,m;
bool bfs()
{
	memset(dep,0,sizeof dep);
	queue<int>q;
	q.push(101);
	dep[101]=1;
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		for(int i=0;i<v[now].size();i++)
		{
			if(v[now][i].cap>0&&dep[v[now][i].to]==0)
			{
				dep[v[now][i].to]=dep[now]+1;
				q.push(v[now][i].to);
			}
		}
	}
	return dep[102]>0;
}
int dfs(int s,int e,int flow)
{
	if(s==e)return flow;//flow为当前可行弧的可行流 
	int f;
	int ff=0;	
	//for(int &i=iter[s];i<v[s].size();i++)2
	for(int i=0;i<v[s].size();i++)//1
	{
		//if(v[s][i].cap>0&&dep[s]==dep[v[s][i].to]-1) 2
		if(v[s][i].cap>0&&flow>ff&&dep[s]==dep[v[s][i].to]-1)//1
		{
			//f=dfs(v[s][i].to,e,min(flow,v[s][i].cap)); 2
			f=dfs(v[s][i].to,e,min(flow-ff,v[s][i].cap));// 1
			if(f>0){
				v[s][i].cap-=f;
				v[v[s][i].to][v[s][i].rev].cap+=f;
				ff+=f;// s点所有可能的流量 
				//return f;2
			}
		}
	}
	if(ff==0)dep[s]=0;//1
	return ff;//1  方法1 相当于把一个点上连接的点全部遍历一遍后再返回 比法内容2要多点 效率稍稍比法2低(法1 110ms 法2 79ms) 但是理解起来非常容易
//	return 0; 2 //方法2 是用了一个 iter 数组来记录 看了好久没看懂  比不优化的代码只多一点点 就多一个i取值和归零
}
int Dinic()
{
	int max_flow=0,flow=0;
	while(bfs())
	{
		//memset(iter,0,sizeof iter); 2
		while(flow=dfs(101,102,inf))
		max_flow+=flow;
	}
	return max_flow;
}
int main()
{
	while(scanf("%d%d%d%d",&n,&np,&nc,&m)!=EOF)
	{
		int s,e,c;
		for(int i=0;i<n;i++)v[i].clear();
		v[101].clear();v[102].clear();
		char cc;
		for(int i=0;i<m;i++)
		{
		       //cin>>cc>>s>>cc>>e>>cc>>c; 用cin输入输出 不用管回车空格的问题 但是非常耗时间跑了差不多800ms 而scanf只用了100ms左右
			scanf(" (%d,%d)%d",&s,&e,&c);
			
			if(s==e)continue;
			v[s].push_back((Edge){e,c,v[e].size()});
			v[e].push_back((Edge){s,0,v[s].size()-1});
		}
		for(int i=0;i<np;i++)
		{			
			//cin>>cc>>e>>cc>>c;
			scanf(" (%d)%d",&e,&c);
			
			v[101].push_back((Edge){e,c,v[e].size()}); 
			v[e].push_back((Edge){101,inf,v[101].size()-1}); 
		}
		for(int i=0;i<nc;i++)
		{			
			//cin>>cc>>e>>cc>>c;				
			scanf(" (%d)%d",&e,&c);
			
			v[102].push_back((Edge){e,inf,v[e].size()}); 
			v[e].push_back((Edge){102,c,v[102].size()-1}); 
		}
		printf("%d\n",Dinic());		
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/swust5120166213/article/details/79767219