首页 > 代码库 > 上下界网络流小结

上下界网络流小结

虽然网上已经有很详细的解释了,但是别人总结的终究是别人的。

1无源无汇上下界的可行流

首先明确定义:B[u, v]和C[u, v]表示边(u,v)的下界容量和上界容量,我们的问题是求一个每条边都具有上下界的可行流。

简单分析:由于每条边要满足下界容量,而且每个点要满足流量平衡,所以就需要对平时的网络流模型改造。

方法一:建立附加远点回电,S,T,对于边(u, v),连边S->v,容量B[u, v], 及u->T, 容量B[u, v], 然后对于本来的边u->v,容量改为C[u, v]-B[u, v],这样对于u,v都可以看做与原来的图等效了,做网络流之后,如果存在可行解,那么S出发的边全部满流。

方法二:sum[u],表示进入u的下界容量之后,sum[u] = sigma{B[i, u]}-sigma{B[u, j]},F[u, v]为实际流过(u, v)的容量,

若sum[u] > 0,  连S->u的边容量为sum[u];

若sum[u] < 0,  连u->T的边容量为-sum[u]。

 ZOJ - 2314

Reactor Cooling
  1 #include <bits/stdc++.h>  2 #define pb push_back  3 #define mp make_pair  4   5 #define lson   l, m, rt<<1  6 #define rson   m+1, r, rt<<1|1  7 #define sz(x) ((int)((x).size()))  8 #define pb push_back  9 #define in freopen("solve_in.txt", "r", stdin); 10 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 11 #define inf 0x0f0f0f0f 12 using namespace std; 13 typedef long long LL; 14 typedef map<int, int> MPS; 15 typedef pair<int, int> PII; 16 const int maxn = 222; 17 struct Node { 18     int c, l, id; 19     Node() {} 20     Node(int c, int l, int id):c(c), l(l), id(id) {} 21 }; 22 vector<Node> cap; 23  24  25 struct Edge { 26     int u, v, c; 27     Edge(int u, int v, int c):u(u), v(v), c(c) {} 28 }; 29 struct Max_flow { 30     int n, m; 31     int src, sink; 32     vector<Edge> edges; 33     vector<int> G[maxn]; 34     int Now[maxn], Dfn[maxn], cur[maxn]; 35     void init(int n) { 36         this->n = n; 37         for(int i = 0; i < n; i++) G[i].clear(); 38         edges.clear(); 39     } 40     void add(int u, int v, int c) { 41         edges.pb(Edge(u, v, c)); 42         edges.pb(Edge(v, u, 0)); 43         m = edges.size(); 44         G[u].pb(m-2); 45         G[v].pb(m-1); 46     } 47     int ISAP(int s, int flow) { 48         if(s == sink) 49             return flow; 50         int i, tab = n, vary, now = 0; 51         int p = cur[s]; 52         do { 53             Edge &e = edges[G[s][cur[s]]]; 54             if(e.c > 0) { 55                 if(Dfn[s] == Dfn[e.v]+1) 56                     vary = ISAP(e.v, min(flow-now, e.c)), 57                     now += vary, e.c -= vary, edges[G[s][cur[s]]^1].c += vary; 58                 if(Dfn[src] == n) 59                     return now; 60                 if(e.c > 0) tab = min(tab, Dfn[e.v]); 61                 if(flow == now) 62                     break; 63             } 64             cur[s]++; 65             if(cur[s] == (int)G[s].size()) cur[s] = 0; 66         } while(p != cur[s]); 67         if(now == 0) { 68             if(--Now[Dfn[s]] == 0) 69                 Dfn[src] = n; 70             Now[Dfn[s] = tab+1]++; 71         } 72         return now; 73     } 74     int max_flow(int src, int sink) { 75         this->src =http://www.mamicode.com/ src; 76         this->sink = sink; 77         int flow = 0; 78         memset(Dfn, 0, sizeof Dfn); 79         memset(Now, 0, sizeof Dfn); 80         memset(cur, 0, sizeof cur); 81         Now[0] = n; 82         for(; Dfn[src] < n;) 83             flow += ISAP(src, inf); 84         return flow; 85     } 86 } mc; 87 vector<int> mx; 88  89 int main() { 90      91     int T; 92     for(int t = scanf("%d", &T); t <= T; t++) { 93         int n, m; 94         cap.clear(); 95         mx.clear(); 96         int ff = 0; 97         scanf("%d%d", &n, &m); 98         mc.init(n+2); 99         int src = http://www.mamicode.com/n, sink = n+1;100 101         for(int i = 1; i <= m; i++) {102             int u, v, c, l;103             scanf("%d%d%d%d", &u, &v, &l, &c);104             ff += l;105             u--, v--;106             mc.add(u, v, c-l);107             int tmp = mc.edges.size()-2;108             cap.pb(Node(c, l, tmp));109             mc.add(src, v, l);110             tmp = mc.edges.size()-2;111             mx.pb(tmp);112             mc.add(u, sink, l);113         }114         int flow = mc.max_flow(src, sink);115 116 //        int ok = 1;117 //        for(int i = 0; i < (int)mx.size(); i++) {118 //            int id = mx[i];119 //            if(mc.edges[id].c) {120 //                ok = 0;121 //                break;122 //            }123 //        }124 125         if(t != 1) puts("");126         if(ff == flow) {127             puts("YES");128             for(int i = 0; i < (int)cap.size(); i++) {129                 Node x = cap[i];130                 int id = x.id;131                 printf("%d\n", x.c-mc.edges[id].c);132             }133         } else puts("NO");134     }135     return 0;136 }
View Code

 

2有源汇上下界流

对于有上下界的网络流,要求其最大或最下流,我们可以针对源汇点连一条容量无穷大的边,这样整个图就变成无源无汇的流量图了。

通常有两种方法:一,二分法,二,直接转化法

1)最大流

二分法:每次设置T到S的边的容量下界,然后判断是否存在可行流,最后是可以得到最大值的。

直接转化法:先连一条T到S的容量无穷的边,然后转化为无源无汇的可行流,做一遍网络流后判断S出边是否满流,如果不满流说明不存在可行解;否则,拆除T到S的边,然后从原图源点src, 汇点sink做网络流,最后结果就是T->S反响变的容量+src到sink的最大流

ZOJ - 3229

Shoot the Bullet
  1 #include <bits/stdc++.h>  2 #define pb push_back  3 #define mp make_pair  4 #define esp 1e-14  5 #define lson   l, m, rt<<1  6 #define rson   m+1, r, rt<<1|1  7 #define sz(x) ((int)((x).size()))  8 #define pf(x) ((x)*(x))  9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 12 #define inf 0x0f0f0f0f 13 using namespace std; 14 typedef long long LL; 15 typedef map<LL, int> MPS; 16 typedef pair<LL, LL> PII; 17 const int maxn = 1555; 18 int num[1111][400]; 19 int l[1111][400], r[1111][400]; 20 vector<int> days[400]; 21  22 struct Edge { 23     int u, v, c; 24     Edge() {} 25     Edge(int u, int v, int c):u(u), v(v), c(c) {} 26 }; 27 struct MaxFlow { 28     int n, m, src, sink; 29     vector<Edge> edges; 30     vector<int> G[maxn]; 31     int Now[maxn], Dfn[maxn]; 32     void init(int n) { 33         this->n = n; 34         for(int i = 0; i < n; i++) 35             G[i].clear(); 36         edges.clear(); 37     } 38     int add(int u, int v, int c) { 39         edges.pb(Edge(u, v, c)); 40         edges.pb(Edge(v, u, 0)); 41         m = edges.size(); 42         G[u].pb(m-2); 43         G[v].pb(m-1); 44         return m; 45     } 46     int ISAP(int s, int flow) { 47         if(s == sink) return flow; 48         int tab = n, v, now = 0, vary; 49         for(int i = 0; i < sz(G[s]); i++) { 50             Edge &e = edges[G[s][i]]; 51             if(e.c > 0) { 52                 if(Dfn[s] == Dfn[v = e.v] + 1) 53                     vary = ISAP(v, min(flow-now, e.c)), 54                     now += vary, e.c -= vary, edges[G[s][i]^1].c += vary; 55                 if(Dfn[src] == n) return now; 56                 if(e.c > 0) tab = min(tab, Dfn[v]); 57                 if(now == flow) break; 58             } 59         } 60         if(now == 0) { 61             if(--Now[Dfn[s]] == 0) 62                 Dfn[src] = n; 63             ++Now[Dfn[s] = tab + 1]; 64         } 65         return now; 66     } 67     int getAns(int src, int sink) { 68         this->src =http://www.mamicode.com/ src; 69         this->sink = sink; 70         memset(Now, 0, sizeof Now); 71         memset(Dfn, 0, sizeof Dfn); 72         Now[0] = n; 73         int ans = 0; 74         while(Dfn[src] < n) { 75             ans += ISAP(src, inf); 76         } 77         return ans; 78     } 79 } solver ; 80 int main() { 81  82     int n, m; 83     while(scanf("%d%d", &n, &m) == 2) { 84         for(int i = 0; i < 400; i++) 85             days[i].clear(); 86         solver.init(n+m+4); 87         int src = http://www.mamicode.com/0, sink = n+m+1; 88         int S = n+m+2, T = S+1; 89         for(int i = 0; i < m; i++) { 90             int lim; 91             scanf("%d", &lim); 92             solver.add(src, i+1, inf-lim); 93             solver.add(S, i+1, lim); 94             solver.add(src, T, lim); 95         } 96         for(int i = 1; i <= n; i++) { 97             int t, c; 98             scanf("%d%d", &t, &c); 99             solver.add(i+m, sink, c);100             for(int j = 1; j <= t; j++) {101                 int no, L, R;102                 scanf("%d%d%d", &no, &L, &R);103                 no++;104                 days[i].pb(no);105                 l[no][i] = L;106                 r[no][i] = R;107                 num[no][i] = solver.add(no, i+m, R-L)-2;108                 solver.add(S, i+m, L);109                 solver.add(no, T, L);110             }111         }112         int tmp = solver.add(sink, src, inf);113         solver.getAns(S, T);114         int ok = 1;115         for(int i = 0; i < sz(solver.G[S]); i++)116             if(solver.edges[solver.G[S][i]].c) {117                 ok = 0;118                 break;119             }120         if(!ok) {121             puts("-1\n");122             continue;123         }124         int ans = 0;125         ans += solver.edges[tmp-1].c;126         solver.edges[tmp-1].c = solver.edges[tmp-2].c = 0;127         ans += solver.getAns(src, sink);128         printf("%d\n", ans);129         for(int i = 1; i <= n; i++)130             for(int j = 0; j < sz(days[i]); j++) {131                 int x = days[i][j];132                 printf("%d\n", l[x][i]+solver.edges[num[x][i]^1].c);133             }134         puts("");135     }136     return 0;137 }
View Code

 

2)最小流

二分法:每次设置T到S的边的容量上界,然后判断是否存在可行流,同样最后是可以得到最小值的。

直接转化法:先不连T到S的边直接转化为无源无汇的可行流判断,然后连接T到S的容量无穷的边,再做一次无源无汇的网络流可行流判断,答案便是T->S反向边的容量。

以上各种方法中,每条边实际流量是容量下界+该边的反向边的容量。

ZOJ - 2567

Trade
  1 #include <bits/stdc++.h>  2 #define pb push_back  3 #define mp make_pair  4 #define esp 1e-14  5 #define lson   l, m, rt<<1  6 #define rson   m+1, r, rt<<1|1  7 #define sz(x) ((int)((x).size()))  8 #define pf(x) ((x)*(x))  9 #define pb push_back 10 #define in freopen("solve_in.txt", "r", stdin); 11 #define bug(x) printf("Line : %u >>>>>>\n", (x)); 12 #define inf 0x0f0f0f0f 13 using namespace std; 14 typedef long long LL; 15 typedef map<LL, int> MPS; 16 typedef pair<LL, LL> PII; 17 const int maxn = 333; 18 int g[maxn][maxn]; 19 int du[maxn*2]; 20  21 struct Edge { 22     int u, v, c; 23     Edge() {} 24     Edge(int u, int v, int c):u(u), v(v), c(c) {} 25 }; 26 struct E { 27     int u, v, b, c; 28     E() {} 29     E(int u, int v, int b, int c):u(u), v(v), b(b), c(c) {} 30 }; 31 vector<E> edge; 32  33 struct MaxFlow { 34     int n, m, src, sink; 35     vector<Edge> edges; 36     vector<int> G[maxn*2]; 37     int Now[maxn*2], Dfn[maxn*2]; 38     void init(int n) { 39         this->n = n; 40         for(int i = 0; i < n; i++) 41             G[i].clear(); 42         edges.clear(); 43     } 44     int add(int u, int v, int c) { 45         edges.pb(Edge(u, v, c)); 46         edges.pb(Edge(v, u, 0)); 47         m = edges.size(); 48         G[u].pb(m-2); 49         G[v].pb(m-1); 50         return m; 51     } 52     int ISAP(int s, int flow) { 53  54         if(s == sink) return flow; 55         int v, tab = n-1, vary, now = 0; 56         for(int i = 0; i < sz(G[s]); i++) { 57             Edge &e = edges[G[s][i]]; 58             if(e.c > 0) { 59                 if(Dfn[s] == Dfn[v = e.v] + 1) 60                     vary = ISAP(v, min(flow-now, e.c)), 61                     now += vary, e.c -= vary, edges[G[s][i]^1].c += vary; 62                 if(Dfn[src] == n) return now; 63                 if(e.c > 0) tab = min(tab, Dfn[v]); 64                 if(now == flow) break; 65             } 66         } 67         if(now == 0) { 68             if(--Now[Dfn[s]] == 0) 69                 Dfn[src] = n; 70             ++Now[Dfn[s] = tab + 1]; 71         } 72         return now; 73     } 74     int getAns(int src, int sink) { 75  76         this->src =http://www.mamicode.com/ src; 77         this->sink = sink; 78         memset(Dfn, 0, sizeof Dfn); 79         memset(Now, 0, sizeof Now); 80         Now[0] = n; 81         int ans = 0; 82         while(Dfn[src] < n) 83             ans += ISAP(src, inf); 84         return ans; 85     } 86  87 } solver; 88  89  90 int main() { 91  92     int n, m, p; 93     while(scanf("%d%d%d", &n, &m, &p) == 3) { 94         int src = http://www.mamicode.com/0, sink = n+m+1; 95         memset(du, 0, sizeof du); 96         int S = n+m+2, T = S+1; 97         edge.clear(); 98         solver.init(n+m+4); 99         for(int i = 1; i <= p; i++) {100             int u, v;101             scanf("%d%d", &u, &v);102             edge.pb(E(u, v+n, 0, 1));103         }104         for(int i = 0; i < n; i++)105             edge.pb(E(src, i+1, 2, inf));106         for(int j = 0; j < m; j++)107             edge.pb(E(j+1+n, sink, 2, inf));108         for(int i = 0; i < sz(edge); i++) {109             E e = edge[i];110             du[e.u] -= e.b;111             du[e.v] += e.b;112             solver.add(e.u, e.v, e.c-e.b);113         }114         for(int i = 0; i < S; i++) {115             if(du[i] > 0)116             solver.add(S, i, du[i]);117             else if(du[i] < 0)118             solver.add(i, T, -du[i]);119         }120         solver.getAns(S, T);121         solver.add(sink, src, inf);122         solver.getAns(S, T);123         int ok = 1;124         for(int i = 0; i < sz(solver.G[S]); i++) {125             Edge e = solver.edges[solver.G[S][i]];126             if(e.c) {127                 ok = 0;128                 break;129             }130         }131         if(!ok) puts("-1");132         else {133             vector<int> ans;134             for(int i = 0; i < p; i++) {135                 if(solver.edges[i<<1|1].c)136                     ans.pb(i+1);137             }138             cout << sz(ans) << endl;139             for(int i = 0; i < sz(ans); i++)140                 printf("%d%c", ans[i], i == sz(ans)-1 ? \n :  );141         }142     }143     return 0;144 }
View Code

 

上下界网络流小结