題目大概說一個核反應堆的冷卻系統有n個結點,有m條單向的管子連接它們,管子內流量有上下界的要求,問能否使液體在整個系統中循環流動。
本質上就是求一個無源匯流量有上下界的容量網絡的可行流,因為無源匯的容量網絡上各個頂點都滿足流量平衡條件,即所有點的∑流入流量=∑流出流量,可以看成里面的流是循環流動的,類似有向圖歐拉回路。
而帶上下界的網絡可行流的求法,是根據網絡流中一個流是可行流的充分必要條件——限制條件和平衡條件,去改造原網絡,轉化成不帶下界的容量網絡來求解的。數學模型那些證明之類的不難理解,見論文《一種簡易的方法求解流量有上下界的網絡中網絡流問題》。
而改造的方式好像有兩種挺流行的,我用的做法是:
- 設d[u]為頂點u出邊下界和-入邊下界和,新建源點、匯點
- 原網絡的弧<u,v>容量設置成其上界-下界
- 對于每一個頂點u,如果d[u]<0則源點向其連容量-d[u]的邊,否則其向匯點連容量d[u]的邊
- 最后如果和源點相關的弧都滿流則存在可行流,而各條邊的流量+其在原網絡的下界就是一個解
1 #include<cstdio>
2 #include<cstring>
3 #include<queue>
4 #include<algorithm>
5 using namespace std;
6 #define INF (1<<30)
7 #define MAXN 222
8 #define MAXM 222*444
9
10 struct Edge{
11 int v,cap,flow,next;
12 }edge[MAXM];
13 int vs,vt,NE,NV;
14 int head[MAXN];
15
16 void addEdge(
int u,
int v,
int cap){
17 edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=
0;
18 edge[NE].next=head[u]; head[u]=NE++
;
19 edge[NE].v=u; edge[NE].cap=
0; edge[NE].flow=
0;
20 edge[NE].next=head[v]; head[v]=NE++
;
21 }
22
23 int level[MAXN];
24 int gap[MAXN];
25 void bfs(){
26 memset(level,-
1,
sizeof(level));
27 memset(gap,
0,
sizeof(gap));
28 level[vt]=
0;
29 gap[level[vt]]++
;
30 queue<
int>
que;
31 que.push(vt);
32 while(!
que.empty()){
33 int u=
que.front(); que.pop();
34 for(
int i=head[u]; i!=-
1; i=
edge[i].next){
35 int v=
edge[i].v;
36 if(level[v]!=-
1)
continue;
37 level[v]=level[u]+
1;
38 gap[level[v]]++
;
39 que.push(v);
40 }
41 }
42 }
43
44 int pre[MAXN];
45 int cur[MAXN];
46 int ISAP(){
47 bfs();
48 memset(pre,-
1,
sizeof(pre));
49 memcpy(cur,head,
sizeof(head));
50 int u=pre[vs]=vs,flow=
0,aug=
INF;
51 gap[
0]=
NV;
52 while(level[vs]<
NV){
53 bool flag=
false;
54 for(
int &i=cur[u]; i!=-
1; i=
edge[i].next){
55 int v=
edge[i].v;
56 if(edge[i].cap!=edge[i].flow && level[u]==level[v]+
1){
57 flag=
true;
58 pre[v]=
u;
59 u=
v;
60 //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
61 aug=min(aug,edge[i].cap-
edge[i].flow);
62 if(v==
vt){
63 flow+=
aug;
64 for(u=pre[v]; v!=vs; v=u,u=
pre[u]){
65 edge[cur[u]].flow+=
aug;
66 edge[cur[u]^
1].flow-=
aug;
67 }
68 //aug=-1;
69 aug=
INF;
70 }
71 break;
72 }
73 }
74 if(flag)
continue;
75 int minlevel=
NV;
76 for(
int i=head[u]; i!=-
1; i=
edge[i].next){
77 int v=
edge[i].v;
78 if(edge[i].cap!=edge[i].flow && level[v]<
minlevel){
79 minlevel=
level[v];
80 cur[u]=
i;
81 }
82 }
83 if(--gap[level[u]]==
0)
break;
84 level[u]=minlevel+
1;
85 gap[level[u]]++
;
86 u=
pre[u];
87 }
88 return flow;
89 }
90 int low[MAXM],d[MAXN];
91 int main(){
92 int t,n,m,a,b,c;
93 scanf(
"%d",&
t);
94 while(t--
){
95 scanf(
"%d%d",&n,&
m);
96 memset(d,
0,
sizeof(d));
97 vs=
0; vt=n+
1; NV=vt+
1; NE=
0;
98 memset(head,-
1,
sizeof(head));
99 for(
int i=
0; i<m; ++
i){
100 scanf(
"%d%d%d%d",&a,&b,low+i,&
c);
101 addEdge(a,b,c-
low[i]);
102 d[a]+=
low[i];
103 d[b]-=
low[i];
104 }
105 int tot=
0;
106 for(
int i=
1; i<=n; ++
i){
107 if(d[i]<
0) addEdge(vs,i,-
d[i]);
108 else addEdge(i,vt,d[i]),tot+=
d[i];
109 }
110 if(ISAP()!=tot) puts(
"NO");
111 else{
112 puts(
"YES");
113 for(
int i=
0; i<m; ++
i){
114 printf(
"%d\n",edge[i<<
1].flow+
low[i]);
115 }
116 }
117 putchar(
'\n');
118 }
119 return 0;
120 }
?
轉載于:https://www.cnblogs.com/WABoss/p/5371871.html
總結
以上是生活随笔為你收集整理的ZOJ2314 Reactor Cooling(无源汇流量有上下界网络的可行流)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。