上下界网络流小结

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

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

  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 >>>>>>
", (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 = 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 = 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
", 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

  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 >>>>>>
", (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 = 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 = 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
");
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
", 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
", 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

  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 >>>>>>
", (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 = 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 = 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 ? '
' : ' ');
141         }
142     }
143     return 0;
144 }
View Code
原文地址:https://www.cnblogs.com/rootial/p/4156173.html