ZOJ 2314 Reactor Cooling(无源汇有上下界可行流)
Posted fu3638
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 2314 Reactor Cooling(无源汇有上下界可行流)相关的知识,希望对你有一定的参考价值。
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314
题目大意:
给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质。
并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li。
解题思路:
转自:https://www.cnblogs.com/WABoss/p/5371871.html
本质上就是求一个无源汇流量有上下界的容量网络的可行流,因为无源汇的容量网络上各个顶点都满足流量平衡条件,即所有点的∑流入流量=∑流出流量,可以看成里面的流是循环流动的,类似有向图欧拉回路。
而带上下界的网络可行流的求法,是根据网络流中一个流是可行流的充分必要条件——限制条件和平衡条件,去改造原网络,转化成不带下界的容量网络来求解的。数学模型那些证明之类的不难理解,见论文《一种简易的方法求解流量有上下界的网络中网络流问题》。
而改造的方式好像有两种挺流行的,我用的做法是:
- 设d[u]为顶点u出边下界和-入边下界和,新建源点、汇点
- 原网络的弧<u,v>容量设置成其上界-下界
- 对于每一个顶点u,如果d[u]<0则源点向其连容量-d[u]的边,否则其向汇点连容量d[u]的边
- 最后如果和源点相关的弧都满流则存在可行流,而各条边的流量+其在原网络的下界就是一个解
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 #include<vector> 8 #define LL long long 9 #define pii pair<int,int> 10 #define pll pair<long long,long long> 11 #define rep(i,a,b) for(int i=a;i<=b;i++) 12 #define per(i,a,b) for(int i=a;i>=b;i--) 13 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 14 #define bug cout<<"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"<<endl; 15 #define bugc(_) cout << (#_) << " = " << (_) << endl; 16 using namespace std; 17 const int N=2e2+5; 18 const int M=4e4+5; 19 const int INF=0x3f3f3f3f; 20 21 struct node{ 22 int to,next,flow; 23 }edge[M*2]; 24 25 int cnt,st,en; 26 int head[N],dep[N],d[N],low[M];//d[u]为顶点u出边下界和-入边下界和,low[i]记录第i条边的下界 27 28 void init(){ 29 cnt=2; 30 memset(head,0,sizeof(head)); 31 memset(d,0,sizeof(d)); 32 } 33 34 void link(int u,int v,int flow){ 35 edge[cnt]=node{v,head[u],flow}; 36 head[u]=cnt++; 37 edge[cnt]=node{u,head[v],0}; 38 head[v]=cnt++; 39 } 40 41 int bfs(){ 42 memset(dep,0,sizeof(dep)); 43 dep[st]=1; 44 queue<int>q; 45 q.push(st); 46 while(!q.empty()){ 47 int u=q.front(); 48 q.pop(); 49 for(int i=head[u];i;i=edge[i].next){ 50 node t=edge[i]; 51 if(t.flow&&!dep[t.to]){ 52 dep[t.to]=dep[u]+1; 53 q.push(t.to); 54 } 55 } 56 } 57 return dep[en]; 58 } 59 60 int dfs(int u,int fl){ 61 if(en==u) return fl; 62 int tmp=0; 63 for(int i=head[u];i&&fl;i=edge[i].next){ 64 node &t=edge[i]; 65 if(t.flow&&dep[t.to]==dep[u]+1){ 66 int x=dfs(t.to,min(t.flow,fl)); 67 if(x>0){ 68 tmp+=x; 69 fl-=x; 70 t.flow-=x; 71 edge[i^1].flow+=x; 72 } 73 } 74 } 75 if(!tmp) dep[u]=-2; 76 return tmp; 77 } 78 79 int dinic(){ 80 int ans=0; 81 while(bfs()){ 82 while(int d=dfs(st,INF)) 83 ans+=d; 84 } 85 return ans; 86 } 87 88 int main(){ 89 int T; 90 scanf("%d",&T); 91 while(T--){ 92 int n,m; 93 scanf("%d%d",&n,&m); 94 init(); 95 st=0,en=n+1; 96 for(int i=1;i<=m;i++){ 97 int u,v,c; 98 scanf("%d%d%d%d",&u,&v,&low[i],&c); 99 link(u,v,c-low[i]); 100 d[u]+=low[i]; 101 d[v]-=low[i]; 102 } 103 int sum=0; 104 for(int i=1;i<=n;i++){ 105 if(d[i]<0) link(st,i,-d[i]); 106 else{ 107 sum+=d[i]; 108 link(i,en,d[i]); 109 } 110 } 111 if(sum!=dinic()) puts("NO"); 112 else{ 113 puts("YES"); 114 for(int i=2;i<=2*m;i+=2){ 115 printf("%d ",edge[i^1].flow+low[i>>1]); 116 } 117 } 118 puts(""); 119 } 120 return 0; 121 }
以上是关于ZOJ 2314 Reactor Cooling(无源汇有上下界可行流)的主要内容,如果未能解决你的问题,请参考以下文章
ZOJ_2314_Reactor Cooling_有上下界可行流模板
Reactor Cooling ZOJ - 2314 上下界网络流