1. 程式人生 > >2314 Reactor Cooling(有上下界網路流)

2314 Reactor Cooling(有上下界網路流)

題目:

給n個點和m個邊,每條邊有流量上界和下界,問能否使這n個點形成一個流量迴圈,每個點流入等於流出,每條邊都在界限之內。

分析:

典型的有上下界無源匯網路流。
法一:
建立源點 ss 和匯點 tt , 對於圖中每條邊 <u,v><u, v> ,拆成如下三條:

  • <s,v><s,v> ,容量為 ll
  • <u,t><u,t> ,容量為 ll
  • <
    u,v><u, v>
    ,容量為 rlr - l
    其中前兩條弧一般稱為附加弧。
    然後對圖跑從 sstt 的最大流,如果所有附加弧都滿流,則有可行流。這時,每條非附加弧的流量加上它的容量下界,就是原圖中這條弧應該有的流量。

法二:
建立源點 ss 和匯點 tt ,對於每條邊建立 <u,v><u,v> 容量為 rlr-l 的邊。此外,對於圖中每個點,令 d[i]=iid[i] = \sum i節點所有入流下界和 - \sum i節點所有出流下界和


d[i]>0d[i] > 0, 建立 <s,i><s,i> 容量為 d[i]d[i] 的邊。
d[i]<0d[i] < 0 ,建立 <i,t><i,t> 容量為 d[i]-d[i] 的邊。
然後跑 sstt 的最大流,若附加邊全部滿流,即 maxflow=d[i
]>0maxflow = \sum d[i] >0
之和,存在可行流。每條邊流量同法一。

其實法一和法二本質是一樣的,但法二建立的邊更少,速度更快。

程式碼:

#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 205;
const int MAXM = 100005;
const int INF=0x3f3f3f3f;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
    return x*f;
}
struct Edge{
	int to,next,cap,flow;
	int id;
}edge[MAXM];
int tot,head[MAXN];
int Q[MAXN],cur[MAXN],dep[MAXN];
int n,m,S,T,N,to[MAXN];
void init(){
	tot = 2;
	memset(head,-1,sizeof head);
}
void addedge(int u, int v, int w, int id, int rw = 0) {
    edge[tot].to = v; edge[tot].cap = w; edge[tot].flow = 0; edge[tot].id = id;
    edge[tot].next = head[u]; head[u] = tot++;
    edge[tot].to = u; edge[tot].cap = rw; edge[tot].flow = 0; edge[tot].id = -1;
    edge[tot].next = head[v]; head[v] = tot++;
}
bool bfs(int s,int t,int n){
	int Front = 0, tail = 0;
	memset(dep,-1,sizeof(dep[0])*(n+1));
	dep[s] = 0;
	Q[tail++] = s;
	while(Front < tail){
		int u = Q[Front++];
		for(int i=head[u];i!=-1;i=edge[i].next){
			int v=edge[i].to;
			if(edge[i].cap > edge[i].flow && dep[v] == -1){
				dep[v] = dep[u]+1;
				if(v==t) return true;
				Q[tail++] = v;
			}
		}
	}
	return false;
}
int dfs(int u,int f){
	if(u==T)	return f;
	int used = 0, rflow = 0;
	for(int i=cur[u];i!=-1;i=edge[i].next){
		cur[u] = i;
		int v = edge[i].to, w = edge[i].cap - edge[i].flow;
		if (w>0 && dep[v] == dep[u]+1){
			if((rflow=dfs(v,min(w,f-used)))){
				used+=rflow;
				edge[i].flow += rflow;
				edge[i^1].flow -= rflow;
				if(used == f)	break;
			}
		}
	}
	if(!used)	dep[u] = -1;
	return used;
}
int dinic(int s,int t,int n){
	int maxflow = 0;
	while(bfs(s,t,n)){
		for(int i=0;i<=n;i++)	cur[i] = head[i];
		maxflow += dfs(s,INF);
	}
	return maxflow;
}
int low[MAXM], d[MAXN], id[MAXM];
int main(){
	// freopen("cooling.in","r",stdin);
	// freopen("cooling.out","w",stdout);
	int kase;
	kase = read();
	while(kase--) {
		n = read(); m = read();
		init();
		for(int i=0;i<=n;i++) d[i] = 0;
		for(int i=0;i<=m;i++) id[i] = 0;
		S = 0, T = n + 1, N = n + 1;
		for(int i=1;i<=m;i++) {
			int u,v,l,r;	u = read(); v = read(); l = read(); r = read();
			addedge(u,v,r-l,i);
			low[i] = l;
			d[u] -= l; d[v] += l;
			id[i] = tot-2;
		}
		int sum = 0;
		for(int i=1;i<=n;i++) {
			if(d[i] > 0 ) {
				sum += d[i];
				addedge(S,i,d[i],-1);
			}else if(d[i] < 0 ) {
				addedge(i,T,-d[i],-1);
			}
		}
		if(dinic(S,T,N) == sum) {
			puts("YES");
			for(int i=1;i<=m;i++) {
				printf("%d\n",low[i] + edge[id[i]].flow);
			}
		}else {
			puts("NO");
		}
		puts("");
	}
	return 0;
}