有上下界的网络流问题

不羁岁月 提交于 2020-01-26 20:53:16

有上下界的网络流问题分为无源汇和有源汇两种。

根据周源的《一种简易的方法求解流量有上下界的网络中网络流问题》

 

无源汇上下界网络流的做法是:

设边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 }
View Code

 

 

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 }
View Code

 

zoj 3229 Shoot the Bullet 有源汇有上下界网络流求最大流

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

题意:

有一个人要给在n天给m个女生拍照,已经在n天结束后,每个女生总共必须要拍至少Gi张照片。在第i天,给出c个目标,k1,k2...kc,表示要给这些女生拍照,并且给出[LkiRki]表示这一天给ki这个目标拍的照片数量要在[LkiRki]范围内。

且在第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 }
View Code

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!