有上下界的网络流问题分为无源汇和有源汇两种。
根据周源的《一种简易的方法求解流量有上下界的网络中网络流问题》
无源汇上下界网络流的做法是:
设边u->v的下界是B(u,v),上界是C(u,v)。
设M(i)为对于i结点的流入i的下界总和-流出i的下界总和。
增设源点s和汇点t。
如果M(i)>=0 连边s->i,容量为M(i)。
如果M(i)<0 连边i->t,容量为-M(i)。
对于图中的原来的边u-v,连边u->v,容量为C(u,v)-B(u,v)。
然后求最大流。如果对于源点出发的所有边都满流,则说明存在一个可行流满足条件。
有源汇有上下界网络流的具体做法是:
1.求可行流
从汇点到源点连一条边,容量为INF,其他与无源汇有上下界网络流的建图方法相同。然后以超级源点和超级汇点为网络流的源和汇求一次最大流。
判断起始于超级源点的边是否全部满流即可。
2.求最大流
从汇点到源点连一条边,容量为INF,其他与无源汇有上下界网络流的建图方法相同。然后以超级源点和超级汇点为网络流的源和汇求一次最大流。
判断起始于超级源点的边是否全部满流,若满流,说明存在可行流。
然后去掉汇点到源点连的边,在原来的基础上以原图中的源点和汇点为网络流的源和汇再求一次最大流即可。
ZOJ 2314 Reactor Cooling 无源汇有上下界求最大流
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314
题意:给出N个点,M条边的有向图,每条边的有上下界规定,问是否存在一个可行流满足条件,如果满足输出YES并输出每条边的流量。
如果不满足输出NO。
1 #include <bits/stdc++.h> 2 using namespace std; 3 int N, M; 4 #define maxn 210 5 const int inf = 0x3f3f3f3f; 6 struct Edge 7 { 8 int from, to, cap, flow; 9 Edge(int f, int t, int c, int fl) 10 { 11 from = f; to = t; cap = c; flow = fl; 12 } 13 }; 14 vector <Edge> edges; 15 vector <int> G[maxn]; 16 int cur[maxn], vis[maxn], d[maxn]; 17 int n, m, s, t; 18 void AddEdge(int from, int to, int cap) 19 { 20 edges.push_back(Edge(from, to, cap, 0)); 21 edges.push_back(Edge(to, from, 0, 0)); 22 m = edges.size(); 23 G[from].push_back(m-2); 24 G[to].push_back(m-1); 25 } 26 bool bfs() 27 { 28 memset(vis, 0, sizeof(vis)); 29 vis[s] = 1; 30 d[s] = 0; 31 queue <int> q; 32 q.push(s); 33 while(!q.empty()) 34 { 35 int u = q.front(); q.pop(); 36 for(int i = 0; i < G[u].size(); i++) 37 { 38 Edge &e = edges[G[u][i]]; 39 if(!vis[e.to] && e.cap > e.flow) 40 { 41 vis[e.to] = 1; 42 d[e.to] = d[u]+1; 43 q.push(e.to); 44 } 45 } 46 } 47 return vis[t]; 48 } 49 int dfs(int x, int a) 50 { 51 if(x == t || a == 0) return a; 52 int flow = 0, f; 53 for(int &i = cur[x]; i < G[x].size(); i++) 54 { 55 Edge &e = edges[G[x][i]]; 56 if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0) 57 { 58 e.flow += f; 59 edges[G[x][i]^1].flow -= f; 60 flow += f; 61 a -= f; 62 if(a == 0) break; 63 } 64 } 65 return flow; 66 } 67 int MaxFlow() 68 { 69 int flow = 0; 70 while(bfs()) 71 { 72 memset(cur, 0, sizeof(cur)); 73 flow += dfs(s, inf); 74 } 75 return flow; 76 } 77 int T; 78 int in[maxn], out[maxn], Mi[maxn]; 79 int low[210*210]; 80 int main() 81 { 82 scanf("%d", &T); 83 while(T--) 84 { 85 //s = 0; t = N+1; 86 edges.clear(); 87 for(int i = s; i <= t; i++) G[i].clear(); 88 scanf("%d%d", &N, &M); 89 s = 0; t = N+1; 90 memset(in, 0, sizeof(in)); 91 memset(out, 0, sizeof(out)); 92 for(int i = 1; i <= M; i++) 93 { 94 int u, v, l, f; 95 scanf("%d%d%d%d", &u, &v, &l, &f); 96 low[i] = l; 97 AddEdge(u, v, f-l); 98 out[u] += l; 99 in[v] += l; 100 } 101 for(int i = 1; i <= N; i++) 102 { 103 Mi[i] = in[i] - out[i]; 104 if(Mi[i] >= 0) AddEdge(s, i, Mi[i]); 105 else AddEdge(i, t, -Mi[i]); 106 } 107 int flow = MaxFlow(); 108 vector <int> ans; 109 bool flag = true; 110 for(int i = 0; i < m; i+=2) 111 { 112 if(edges[i].from == s && edges[i].cap > edges[i].flow) 113 { 114 flag = false; break; 115 } 116 else if(edges[i].from != s && edges[i].to != t) 117 { 118 ans.push_back(edges[i].flow); 119 } 120 } 121 if(flag) 122 { 123 printf("YES\n"); 124 for(int i = 0; i < ans.size(); i++) 125 { 126 printf("%d\n", ans[i]+low[i+1]); 127 } 128 } 129 else printf("NO\n"); 130 } 131 return 0; 132 }
poj 2396 Budget 有源汇有上下界网络流求可行流
题目链接:http://poj.org/problem?id=2396
题意:
给出一个N*M的矩阵。已知每行的和以及每列的和。
并对矩阵中的一些数有限制条件,问是否存在这样的矩阵,如果有输出任意解,否则输出"IMPOSSIBLE"。
思路:
这题以每行和每列为一个点建图,增设源点S = 0 汇点T = N+M+1。超级源点SS = N+M+2, 超级汇点N+M+3。
按照无源汇的情况建图,然后再在T->S连接一条容量为inf的边,由于是求可行流,所以求一次最大流就可以了。
要注意的是,在题中给出限制条件的时候,如果对于某个点,它的最小值>最大值了,那么这种情况,一定没有可行解。所以可以先跳出了。如果不跳出求最大流的话会TLE。
1 /* 2 * Problem: poj 2396 3 * Created Time: 2015/10/8 16:39:23 4 * File Name: xixi.cpp 5 */ 6 #include <iostream> 7 #include <cstring> 8 #include <cstdio> 9 #include <vector> 10 #include <queue> 11 using namespace std; 12 #define maxn 250 13 const int inf = 0x3f3f3f3f; 14 struct Edge 15 { 16 int from, to, cap, flow; 17 Edge(int f, int t, int c, int fl) 18 { 19 from = f; to = t; cap = c; flow = fl; 20 } 21 }; 22 vector <Edge> edges; 23 vector <int> G[maxn]; 24 int cur[maxn], vis[maxn], d[maxn]; 25 int n, m, s, t; 26 void AddEdge(int from, int to, int cap) 27 { 28 edges.push_back(Edge(from, to, cap, 0)); 29 edges.push_back(Edge(to, from, 0, 0)); 30 m = edges.size(); 31 G[from].push_back(m-2); 32 G[to].push_back(m-1); 33 } 34 bool bfs() 35 { 36 memset(vis, 0, sizeof(vis)); 37 vis[s] = 1; 38 d[s] = 0; 39 queue <int> q; 40 q.push(s); 41 while(!q.empty()) 42 { 43 int u = q.front(); q.pop(); 44 for(int i = 0; i < G[u].size(); i++) 45 { 46 Edge &e = edges[G[u][i]]; 47 if(!vis[e.to] && e.cap - e.flow > 0) 48 { 49 vis[e.to] = 1; 50 d[e.to] = d[u]+1; 51 q.push(e.to); 52 } 53 } 54 } 55 return vis[t]; 56 } 57 int dfs(int x, int a) 58 { 59 if(x == t || a == 0) return a; 60 int flow = 0, f; 61 for(int &i = cur[x]; i < G[x].size(); i++) 62 { 63 Edge &e = edges[G[x][i]]; 64 if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0) 65 { 66 e.flow += f; 67 edges[G[x][i]^1].flow -= f; 68 flow += f; 69 a -= f; 70 if(a == 0) break; 71 } 72 } 73 return flow; 74 } 75 int MaxFlow() 76 { 77 int flow = 0; 78 while(bfs()) 79 { 80 memset(cur, 0, sizeof(cur)); 81 flow += dfs(s, inf); 82 } 83 return flow; 84 } 85 int cast, N, M; 86 int in[maxn], out[maxn], MM[maxn]; 87 int mpR[210][25], mpL[210][25]; 88 int ans[210][25]; 89 int main() 90 { 91 //freopen("in.txt", "r", stdin); 92 //freopen("out.txt", "w", stdout); 93 scanf("%d", &cast); 94 while(cast--) 95 { 96 scanf("%d%d", &N, &M); 97 int S = 0, T = N+M+1, SS = N+M+2, TT = N+M+3; 98 edges.clear(); 99 for(int i = 0; i <= N+M+3; i++) G[i].clear(); 100 int sum = 0; 101 memset(in, 0, sizeof(in)); 102 memset(out, 0, sizeof(out)); 103 memset(mpL, 0, sizeof(mpL)); 104 memset(mpR, 0x3f3f3f3f, sizeof(mpR)); 105 106 for(int i = 1; i <= N; i++) 107 { 108 int temp; scanf("%d", &temp); 109 AddEdge(S, i, 0); //temp-temp 110 in[i] += temp; 111 out[S] += temp; 112 } 113 for(int i = 1; i <= M; i++) 114 { 115 int temp; scanf("%d", &temp); 116 AddEdge(i+N, T, 0); 117 in[T] += temp; 118 out[i+N] += temp; 119 } 120 int c; scanf("%d", &c); 121 bool flag = false; 122 while(c--) 123 { 124 int a, b, val; char op[10]; 125 scanf("%d%d%s%d", &a, &b, &op, &val); 126 if(op[0] == '>') 127 { 128 if(a != 0 && b != 0) 129 { 130 mpL[a][b] = max(mpL[a][b], val+1); 131 if(mpL[a][b] > mpR[a][b]) flag = true; 132 } 133 else if(a == 0 && b == 0) 134 { 135 for(int i = 1; i <= N; i++) for(int j = 1; j <= M; j++) 136 { 137 mpL[i][j] = max(mpL[i][j],val+1); if(mpL[i][j] > mpR[i][j]) flag = true; 138 } 139 } 140 else if(a == 0 && b != 0) 141 { 142 for(int i = 1; i <= N; i++) { mpL[i][b] = max(mpL[i][b], val+1);if(mpL[i][b] > mpR[i][b]) flag = true;} 143 } 144 else if(a != 0 && b == 0) 145 { 146 for(int i = 1; i <= M; i++) { mpL[a][i] = max(mpL[a][i], val+1); if(mpL[a][i] > mpR[a][i]) flag = true;} 147 } 148 } 149 else if(op[0] == '<') 150 { 151 if(a != 0 && b != 0) 152 { 153 mpR[a][b] = min(mpR[a][b], val-1); 154 if(mpL[a][b] > mpR[a][b]) flag = true; 155 } 156 else if(a == 0 && b == 0) 157 { 158 for(int i = 1; i <= N; i++) for(int j = 1; j <= M; j++) { mpR[i][j] = min(mpR[i][j], val-1); if(mpL[i][j] > mpR[i][j]) flag = true;} 159 } 160 else if(a == 0 && b != 0) 161 { 162 for(int i = 1; i <= N; i++) { mpR[i][b] = min(mpR[i][b], val-1); if(mpL[i][b] > mpR[i][b]) flag = true;} 163 } 164 else if(a != 0 && b == 0) 165 { 166 for(int i = 1; i <= M; i++) { mpR[a][i] = min(mpR[a][i], val-1); if(mpL[a][i] > mpR[a][i]) flag = true;} 167 } 168 } 169 else if(op[0] == '=') 170 { 171 if(a != 0 && b != 0) mpR[a][b] = mpL[a][b] = val; 172 else if(a == 0 && b == 0) 173 { 174 for(int i = 1; i <= N; i++) for(int j = 1; j <= M; j++) mpL[i][j] = mpR[i][j] = val; 175 } 176 else if(a == 0 && b != 0) 177 { 178 for(int i = 1; i <= N; i++) mpL[i][b] = mpR[i][b] = val; 179 } 180 else if(a != 0 && b == 0) 181 { 182 for(int i = 1; i <= M; i++) mpL[a][i] = mpR[a][i] = val; 183 } 184 } 185 } 186 if(flag) 187 { 188 printf("IMPOSSIBLE\n\n"); continue; 189 } 190 for(int i = 1; i <= N; i++) 191 { 192 for(int j = 1; j <= M; j++) 193 { 194 out[i] += mpL[i][j]; 195 in[j+N] += mpL[i][j]; 196 AddEdge(i, j+N, mpR[i][j] - mpL[i][j]); 197 } 198 } 199 sum = 0; 200 for(int i = 0; i <= N+M+1; i++) 201 { 202 MM[i] = in[i] - out[i]; 203 if(MM[i] >= 0 ) 204 { 205 sum += MM[i]; 206 AddEdge(SS, i, MM[i]); 207 } 208 else AddEdge(i, TT, -MM[i]); 209 } 210 AddEdge(T, S, inf); 211 s = SS; t = TT; 212 int flow = MaxFlow(); 213 if(flow != sum) 214 { 215 printf("IMPOSSIBLE\n"); 216 } 217 else 218 { 219 for(int i = 0; i < edges.size(); i+=2) 220 { 221 if(edges[i].from != SS && edges[i].from != S && edges[i].to != T && edges[i].to != TT) 222 { 223 ans[edges[i].from][edges[i].to-N] = edges[i].flow + mpL[edges[i].from][edges[i].to-N]; 224 } 225 } 226 for(int i = 1; i <= N; i++) 227 { 228 for(int j = 1; j <= M; j++) 229 { 230 if(j == 1) printf("%d", ans[i][j]); 231 else printf(" %d", ans[i][j]); 232 } 233 printf("\n"); 234 } 235 } 236 printf("\n"); 237 238 } 239 return 0; 240 }
zoj 3229 Shoot the Bullet 有源汇有上下界网络流求最大流
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3442
题意:
有一个人要给在n天给m个女生拍照,已经在n天结束后,每个女生总共必须要拍至少Gi张照片。在第i天,给出c个目标,k1,k2...kc,表示要给这些女生拍照,并且给出[Lki, Rki]表示这一天给ki这个目标拍的照片数量要在[Lki, Rki]范围内。
且在第i天,不能拍大于Di张照片。问最多能拍多少张照片。如果没有情况可以满足条件,则输出-1。
思路:
首先以N天(1~N)和M个女生(N+1~N+M)建点。增设源点S = 0,和超级汇点T = N+M+1。
考虑第i天最多只能拍Di张照片,所以连边S->i,上限为Di,下限为0,所以容量为Di-0 = Di。
考虑第i个女生至少要拍Gi张照片,所以连边i+N->T,上限为inf,下限为Gi,所以容量为inf - Gi。
对于第i天,和给出的c个目标连边,对于每个目标,上限为Rki,下限为Lki,所以容量为Rki-Lki。
然后增设超级源点SS = N+M+2, 超级汇点T = N+M+3.
计算每个节点(0~N+M+1)的流入节点下限和-流出节点的下限和的值M(i)。
M(i)>=0,连接边SS->i,容量为M(i)
M(i)<0,连边i->TT,容量为-M(i)。
最后再连边T->S,容量为inf。
然后以SS和TT为网络流的源和汇求最大流。判断从超级源点连出的边是否全部满流。如果不是则输出-1,跳出。
否则删除边T->S,以S和T为网络流的源和汇在原来的基础上再求一次最大流。
每条边的流量值就为此时边上的流量+该边下界
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 1500 4 const int inf = 0x3f3f3f3f; 5 struct Edge 6 { 7 int from, to, cap, flow; 8 Edge(int f, int t, int c, int fl) 9 { 10 from = f; to = t; cap = c; flow = fl; 11 } 12 }; 13 vector <Edge> edges; 14 vector <int> G[maxn]; 15 int cur[maxn], vis[maxn], d[maxn]; 16 int n, m, s, t; 17 void AddEdge(int from, int to, int cap) 18 { 19 edges.push_back(Edge(from, to, cap, 0)); 20 edges.push_back(Edge(to, from, 0, 0)); 21 m = edges.size(); 22 G[from].push_back(m-2); 23 G[to].push_back(m-1); 24 } 25 bool bfs() 26 { 27 memset(vis, 0, sizeof(vis)); 28 vis[s] = 1; 29 d[s] = 0; 30 queue <int> q; 31 q.push(s); 32 while(!q.empty()) 33 { 34 int u = q.front(); q.pop(); 35 for(int i = 0; i < G[u].size(); i++) 36 { 37 Edge &e = edges[G[u][i]]; 38 if(!vis[e.to] && e.cap > e.flow) 39 { 40 vis[e.to] = 1; 41 d[e.to] = d[u]+1; 42 q.push(e.to); 43 } 44 } 45 } 46 return vis[t]; 47 } 48 int dfs(int x, int a) 49 { 50 if(x == t || a == 0) return a; 51 int flow = 0, f; 52 for(int &i = cur[x]; i < G[x].size(); i++) 53 { 54 Edge &e = edges[G[x][i]]; 55 if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(e.cap - e.flow, a))) > 0) 56 { 57 e.flow += f; 58 edges[G[x][i]^1].flow -= f; 59 flow += f; 60 a -= f; 61 if(a == 0) break; 62 } 63 } 64 return flow; 65 } 66 int MaxFlow() 67 { 68 int flow = 0; 69 while(bfs()) 70 { 71 memset(cur, 0, sizeof(cur)); 72 flow += dfs(s, inf); 73 } 74 return flow; 75 } 76 int N, M; 77 int ss, tt; 78 int Gi[1010]; 79 int in[1400], out[1400], MM[1400], low[370*100]; 80 int Di[370]; 81 int main() 82 { 83 while(~scanf("%d%d", &N, &M)) 84 { 85 edges.clear(); 86 for(int i = 0; i <= N+M+3; i++) G[i].clear(); 87 88 int S = 0, T = N+M+1; 89 int SS = N+M+2, TT = N+M+3; 90 91 memset(in, 0, sizeof(in)); 92 memset(out, 0, sizeof(out)); 93 for(int i = 1; i <= M; i++) 94 { 95 scanf("%d", &Gi[i]); 96 AddEdge(N+i, T, inf); 97 out[N+i] += Gi[i]; //流出Girl的下界和 98 in[T] += Gi[i]; //流入T的下界和 99 } 100 int tsum = 0; 101 int cnt = 0; 102 for(int i = 1; i <= N; i++) 103 { 104 int c, d; 105 scanf("%d%d", &c, &d); 106 Di[i] = d; 107 tsum += c; 108 out[S] += 0; //流出T的下界和 109 for(int j = 1; j <= c; j++) 110 { 111 cnt++; 112 int tar, l, r; 113 scanf("%d%d%d", &tar, &l, &r); 114 tar++; 115 low[cnt] = l; 116 AddEdge(i, tar+N, r-l); 117 out[i] += l; //流出天数的下界和 118 in[tar+N] += l; //流入Girl的下界和 119 } 120 } 121 for(int i = 1; i <= N; i++) AddEdge(S, i, Di[i]); 122 123 int sum = 0; 124 for(int i = 0; i <= N+M+1; i++) 125 { 126 MM[i] = in[i] - out[i]; 127 if(MM[i] >= 0) 128 { 129 sum += MM[i]; 130 AddEdge(SS, i, MM[i]); 131 } 132 else AddEdge(i, TT, -MM[i]); 133 } 134 AddEdge(T, S, inf); 135 s = SS; t = TT; 136 int flow = MaxFlow(); 137 if(flow != sum) 138 { 139 printf("-1\n"); 140 } 141 else 142 { 143 s = S; t = T; 144 edges.erase(edges.end()); 145 edges.erase(edges.end()); 146 m = edges.size(); 147 int flow = MaxFlow(); 148 printf("%d\n", flow); 149 int cnt = 1; 150 for(int i = 2*M; i < M*2+tsum*2; i+=2) 151 { 152 printf("%d\n", edges[i].flow + low[cnt++]); 153 } 154 } 155 printf("\n"); 156 } 157 158 }
来源:https://www.cnblogs.com/titicia/p/4858680.html