您的位置:首页 > 理论基础 > 计算机网络

ZOJ 3229 有源汇上下界网络流

2014-04-07 17:55 281 查看
有源汇上下界网络流建图:

我们称原图中的源汇点为 from, to

称我们手动附加的源汇点为 S, T

1、首先由给定的图建好上界的边

2、for(i = from; i <= to; i++) if(in[i] > 0) add( S, i, in[i]);

如此把原图中所有点(包括 from, to )按照无源汇上下界与 S,T 连边

3、加一条 边 add(to, from, inf);

建图完成。

跑一遍网络流 maxflow = dinic( S, T);

很显然若存在一个可行流:1、则于S相连的边必须满流 2、或者 maxflow == sum(in[i] (if in[i]>0) )

此时我们就得到了一个 从 from -> to 的一个可行流(并不是最大流)

我们再恢复原图(就是删除第3条) 通过 add(to, from, -inf) 来删除

再跑一遍网络流 dinic(from, to); 即得到 从from->to的一个最大流

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;

#define ll int 

#define N 10004
#define M 105000
#define inf 1073741824
#define inf64 1152921504606846976
struct Edge{  
	ll from, to, cap, nex, max;  
}edge[M*4];//注意这个一定要够大 不然会re 还有反向弧  

ll head
, edgenum;  
void add(ll u, ll v, ll cap){  
	Edge E = { u, v, cap, head[u],cap};  
	edge[ edgenum ] = E;  
	head[u] = edgenum ++;  

	Edge E2= { v, u, 0,   head[v],cap};  
	edge[ edgenum ] = E2;  
	head[v] = edgenum ++;  
}  
ll sign
;  
bool BFS(ll from, ll to){  
	memset(sign, -1, sizeof(sign));  
	sign[from] = 0;  

	queue<ll>q;  
	q.push(from);  
	while( !q.empty() ){  
		int u = q.front(); q.pop();  
		for(ll i = head[u]; i!=-1; i = edge[i].nex)  
		{  
			ll v = edge[i].to;  
			if(sign[v]==-1 && edge[i].cap)  
			{  
				sign[v] = sign[u] + 1, q.push(v);  
				if(sign[to] != -1)return true;  
			}  
		}  
	}  
	return false;  
}  
ll Stack
, top, cur
;  
ll dinic(ll from, ll to){  

	ll ans = 0;  
	while( BFS(from, to) )  
	{  
		memcpy(cur, head, sizeof(head));  
		ll u = from;      top = 0;  
		while(1)  
		{  
			if(u == to)  
			{  
				ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边  
				for(ll i = 0; i < top; i++)  
					if(flow > edge[ Stack[i] ].cap)  
					{  
						flow = edge[Stack[i]].cap;  
						loc = i;  
					}  

					for(ll i = 0; i < top; i++)  
					{  
						edge[ Stack[i] ].cap -= flow;  
						edge[Stack[i]^1].cap += flow;  
					}  
					ans += flow;  
					top = loc;  
					u = edge[Stack[top]].from;  
			}  
			for(ll i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标  
				if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;  
			if(cur[u] != -1)  
			{  
				Stack[top++] = cur[u];  
				u = edge[ cur[u] ].to;  
			}  
			else  
			{  
				if( top == 0 )break;  
				sign[u] = -1;  
				u = edge[ Stack[--top] ].from;  
			}  
		}  
	}  
	return ans;  
}  
int n, m;
int in[M];
int ST[M], sig[M];
void init(){memset(in, 0, sizeof in);memset(head,-1,sizeof head);edgenum = 0;}
int main(){
	int i, j, u, v, cap, peo, maxpic;
	while(~scanf("%d %d",&n,&m)){
		init();
		int from = 0, to = n+m+1;

		for(i = 1; i <= m; i++){
			scanf("%d",&cap);
			add(i+n, to, inf);
			in[to] += cap;
			in[i+n] -= cap;
		}
		int TOP = 0;
		for(i = 1; i <= n; i++)
		{
			scanf("%d %d",&peo, &maxpic);
			add(from, i, maxpic);
			while(peo--)
			{
				int num, Min, Max;
				scanf("%d %d %d",&num, &Min, &Max);
				add(i, num+n+1, Max-Min);
				in[i] -= Min;
				in[num+n+1] += Min;
				sig[TOP] = edgenum-2;
				ST[TOP++] = Min;
			}
		}
		add(to, from, inf);
		int S = to +1, T = to +2;
		int sum = 0;	
		for(i = from; i <= to; i++)
		{
			if(in[i] > 0)
				add(S, i, in[i]), sum += in[i];
			else
				add(i, T, -in[i]);
		}
		ll maxflow = dinic(S, T);
		if(sum != maxflow)puts("-1");
		else {
			maxflow = dinic(from, to);
			add(to, from, -inf);
			int cnt = 0;
			for(i = head[from]; ~i; i = edge[i].nex)
				cnt += edge[i^1].cap;
			printf("%d\n", cnt);
			
			for(i = 0; i < TOP; i++)printf("%d\n", edge[sig[i]^1].cap + ST[i]);
		}
		puts("");
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: