ZOJ 2314 - Reactor Cooling - [无源汇上下界可行流]

时间:2022-04-18 13:36:23

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314

The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuclear reactor to produce plutonium for the nuclear bomb they are planning to create. Being the wicked computer genius of this group, you are responsible for developing the cooling system for the reactor.

The cooling system of the reactor consists of the number of pipes that special cooling liquid flows by. Pipes are connected at special points, called nodes, each pipe has the starting node and the end point. The liquid must flow by the pipe from its start point to its end point and not in the opposite direction.

Let the nodes be numbered from 1 to N. The cooling system must be designed so that the liquid is circulating by the pipes and the amount of the liquid coming to each node (in the unit of time) is equal to the amount of liquid leaving the node. That is, if we designate the amount of liquid going by the pipe from i-th node to j-th as fij, (put fij = 0 if there is no pipe from node i to node j), for each i the following condition must hold:

i,1+f i,2+...+f i,N = f 1,i+f 2,i+...+f N,i

Each pipe has some finite capacity, therefore for each i and j connected by the pipe must be fij <= cij where cij is the capacity of the pipe. To provide sufficient cooling, the amount of the liquid flowing by the pipe going from i-th to j-th nodes must be at least lij, thus it must be fij >= lij.

Given cij and lij for all pipes, find the amount fij, satisfying the conditions specified above.

This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.

Input

The first line of the input file contains the number N (1 <= N <= 200) - the number of nodes and and M - the number of pipes. The following M lines contain four integer number each - i, j, lij and cij each. There is at most one pipe connecting any two nodes and 0 <= lij <= cij <= 10^5 for all pipes. No pipe connects a node to itself. If there is a pipe from i-th node to j-th, there is no pipe from j-th node to i-th.

Output

On the first line of the output file print YES if there is the way to carry out reactor cooling and NO if there is none. In the first case M integers must follow, k-th number being the amount of liquid flowing by the k-th pipe. Pipes are numbered as they are given in the input file.

Sample Input

2

4 6
1 2 1 2
2 3 1 2
3 4 1 2
4 1 1 2
1 3 1 2
4 2 1 2

4 6
1 2 1 3
2 3 1 3
3 4 1 3
4 1 1 3
1 3 1 3
4 2 1 3

Sample Input

NO

YES
1
2
3
2
1
1

题意:

一个核反应堆的冷却系统有 $n$ 个结点,有 $m$ 条单向的管子连接它们,管子内流量有上下界限,问能否使液体在整个系统中循环流动。

题解:

根据论文《一种简易的方法求解流量有上下界的网络中网络流问题》,如果我们在网络流的基础定义上添加一下条件,就可以构造容量有上下界的网络流:

对于网络 $G=(V,E,B,C)$,对于任意一条有向边 $(u,v) \in E$,$b(u,v)$ 代表其容量下界,$c(u,v)$ 则依然代表其容量上界,

那么网络 $G=(V,E,B,C)$ 中的可行流,在依然满足反对称性流量守恒的基础上,对容量限制则稍作添加:对于 $\forall u,v \in V$,要求 $b(u,v) \le f(u,v) \le c(u,v)$。

相应的,也可以定义最小流概念,即所有可行流中流值最小的。

本题的网络中,没有设置源汇点,但是所有点都必须满足流量守恒性质,这类问题叫做无源汇上下界可行流

普通的最大流,仅仅要求 $f(u,v) \ge 0$,那么,不妨设一个一个新流

$g\left( {u,v} \right) = f\left( {u,v} \right) - b\left( {u,v} \right)$

这样一来,由于要求 $g\left( {u,v} \right) \ge 0$,那么实际的流就可以满足 $f(u,v) \ge b(u,v)$,

那么,容易得到新流的上界为

$c\left( {u,v} \right) - b\left( {u,v} \right)$

然而,这样一来,我们实际上构造了一个新网络 $G' = (V,E,C - B)$,它仅仅缩小了每条边的容量上界,依然体现不了下界对于流的限制,

所以我们还需要将式子 $g\left( {u,v} \right) = f\left( {u,v} \right) - b\left( {u,v} \right)$ 代入流量守恒的式子中,得到

$\sum\limits_{(u,i) \in E} {[g(u,i) + b(u,i)]} = \sum\limits_{(i,v) \in E} {[g(i,v) + b(i,v)]}$

$\sum\limits_{(i,v) \in E} {g(i,v)} - \sum\limits_{(u,i) \in E} {g(u,i)} = \sum\limits_{(u,i) \in E} {b(u,i)} - \sum\limits_{(i,v) \in E} {b(i,v)}$

此时,上式左边代表了节点的流出量减去流入量,而右边则是节点的入弧下界和减去出弧下界和,我们记等式右边为 $M(i)$,即

$M(i) = \sum\limits_{(u,i) \in E} {b(u,i)} - \sum\limits_{(i,v) \in E} {b(i,v)}$

若 $M(i) \ge 0$,则

$M(i) + \sum\limits_{(u,i) \in E} {g(u,i)} = \sum\limits_{(i,v) \in E} {g(i,v)}$

若 $M(i) < 0$,则

$\sum\limits_{(u,i) \in E} {g(u,i)} = \sum\limits_{(i,v) \in E} {g(i,v)} - M(i)$

将上面两式与普通的流量守恒式子 $\sum\limits_{(u,i) \in E} {f(u,i)} = \sum\limits_{(i,v) \in E} {f(i,v)}$ 比较发现,

对于新网络 $G' = (V,E,C - B)$ 的流,其流量守恒性质遭到破坏(或者说,要求另一种新的流量平衡),

那么,我们怎么判断这种新的流量平衡是否被满足了呢,很简单,先构建源汇点,

对于 $M(i) \ge 0$,$M(i) + \sum\limits_{(u,i) \in E} {g(u,i)} = \sum\limits_{(i,v) \in E} {g(i,v)}$ 这种情况的节点,建有向边 $(s,i)$,其容量 $c(s,i)$ 为 $M(i)$;

对于 $M(i) < 0$,$\sum\limits_{(u,i) \in E} {g(u,i)} = \sum\limits_{(i,v) \in E} {g(i,v)} - M(i)$ 这种情况的节点,建有向边 $(i,t)$,其容量 $c(i,t)$ 为 $- M(i)$;

这样,当我们对这个网络进行普通的求最大流后,若所有连接源点和汇点的弧都是满流的,那么就代表这种新的流量平衡已经满足了。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=+;
const int maxm=maxn*maxn; struct Edge{
int u,v,c,f;
};
struct Dinic
{
int s,t; //源点汇点
vector<Edge> E;
vector<int> G[maxn];
void init(int l,int r)
{
E.clear();
for(int i=l;i<=r;i++) G[i].clear();
}
int addedge(int from,int to,int cap)
{
E.push_back((Edge){from,to,cap,});
E.push_back((Edge){to,from,,});
G[from].push_back(E.size()-);
G[to].push_back(E.size()-);
return E.size()-;
}
int dist[maxn],vis[maxn];
queue<int> q;
bool bfs() //在残量网络上构造分层图
{
memset(vis,,sizeof(vis));
while(!q.empty()) q.pop();
q.push(s);
dist[s]=;
vis[s]=;
while(!q.empty())
{
int now=q.front(); q.pop();
for(int i=;i<G[now].size();i++)
{
Edge& e=E[G[now][i]]; int nxt=e.v;
if(!vis[nxt] && e.c>e.f)
{
dist[nxt]=dist[now]+;
q.push(nxt);
vis[nxt]=;
}
}
}
return vis[t];
}
int dfs(int now,int flow)
{
if(now==t || flow==) return flow;
int rest=flow,k;
for(int i=;rest> && i<G[now].size();i++)
{
Edge &e=E[G[now][i]]; int nxt=e.v;
if(e.c>e.f && dist[nxt]==dist[now]+)
{
k=dfs(nxt,min(rest,e.c-e.f));
if(!k) dist[nxt]=; //剪枝,去掉增广完毕的点
e.f+=k; E[G[now][i]^].f-=k;
rest-=k;
}
}
return flow-rest;
}
int mf; //存储最大流
int maxflow()
{
mf=;
int flow=;
while(bfs()) while(flow=dfs(s,INF)) mf+=flow;
return mf;
}
}dc; int n,m;
int B[maxm];
int M[maxn];
int Eidx[maxm];
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m); dc.s=,dc.t=n+;
dc.init(,n+); memset(M,,sizeof(M));
for(int u,v,b,c,i=;i<=m;i++)
{
scanf("%d%d%d%d",&u,&v,&b,&c);
Eidx[i]=dc.addedge(u,v,c-b);
B[i]=b;
M[v]+=b;
M[u]-=b;
} int tmp=;
for(int i=;i<=n;i++)
{
if(M[i]>=) dc.addedge(dc.s,i,M[i]),tmp+=M[i];
else dc.addedge(i,dc.t,-M[i]);
}
dc.maxflow(); if(dc.mf!=tmp) printf("NO\n");
else
{
printf("YES\n");
for(int i=;i<=m;i++)
{
printf("%d\n",dc.E[Eidx[i]].f+B[i]);
}
}
printf("\n");
}
}