上下界网络流小结

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

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 = 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\n", x.c-mc.edges[id].c);
132             }
133         } else puts("NO");
134     }
135     return 0;
136 }

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 = 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\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 }

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 = 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 ? ‘\n‘ : ‘ ‘);
141         }
142     }
143     return 0;
144 }

时间: 2024-10-13 11:23:07

上下界网络流小结的相关文章

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

ZOJ3229题目大意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝可以和C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 解题思路:        1.增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为正无穷的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边.        2.

【有上下界网络流】【ZOJ】2314 Reactor Cooling

[算法]有上下界网络流-无源汇(循环流) [题解] 无源汇网络流相当于重建图后跑最大流. 循环流要求每个点(或边)的流入量和流出量相等. http://www.cnblogs.com/liu-runda/p/6262832.html http://hzwer.com/3356.html 入度>出度时(in[x]>0)时,需要流出去,所以从源向点引一条边,引诱它流出去. 入度<出度时(in[x]<0)时,需要流进来,所以从点向汇引一条边,引诱它流进来. 为何这样正确?源和汇的作用只是

acdream 1211 Reactor Cooling 【上下界网络流 + 输出流量】

题目:acdream 1211 Reactor Cooling 分类:无源无汇的有上下界网络流. 题意: 给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质. 并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li. 例如: 46(4个点,6个pipe) 12 1 3 (1->2上界为3,下界为1) 23 1 3

上下界网络流总结

1.无源汇上下界可行流 对于(u,v)有向边,上界为a,下界为b 构图方法为: (1) ss 到 v 容量为 b (2) u 到 tt 容量为 b (3) u 到 v 容量为 a-b 求ss-tt最大流,当且仅当 maxflow=sigma(i,t)=sigma(s,i) 时 存在可行流 2.有源汇上下界最小流 如果发现原图无源汇,要先转化为有源汇 其他点如1方法,建图,另加 t-s 容量为 inf 求一遍 ss-tt最大流,此时s-t的流量为 t-s这条边的反向边的流量,记为 x 在残量网络中

ZOJ 2314 Reactor Cooling 无源汇有上下界网络流

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意:给出N个点,M条边的有向图,每条边的有上下界规定,问是否存在一个可行流满足条件,如果满足输出YES并输出每条边的流量. 如果不满足输出NO. 根据周源的<一种简易的方法求解流量有上下界的网络中网络流问题> 无源汇上下界网络流的做法是: 设边u->v的下界是B(u,v),上界是C(u,v). 设M(i)为对于i结点的流入i的下界总和-流出i的下界总

ZOJ Problem Set - 3229 Shoot the Bullet 【有上下界网络流+流量输出】

题目:ZOJ Problem Set - 3229 Shoot the Bullet 分类:有源有汇有上下界网络流 题意:有 n 天和 m 个girls,然后每天给一部分girls拍照,每个girls 有拍照的下限,即最少要拍这么多张,然后每天有k个女孩拍照,摄影师最多可以拍num张,然后 k 个女该每天拍照数量值有上下限,然后问你有没有满足这样条件的给女孩拍照的最大方案,然后按照输入输出每天给女孩拍照的张数. 做这道题目推荐先做:这儿 分析:首先它让你判断能不能满足条件. 按照题目给出的条件很

Note:上下界网络流的理解

无源汇可行流 弧流量限制条件 b(u,v)<=f(u,v)<=c(u,v),(u,v)∈E 不妨设f(u,v)=b(u,v)+f1(u,v), Σ( b(u,v)+f1(u,v) ) = Σ( b(v,w)+f1(v,w) ) Σ b(u,v) - Σ b(v,w) = Σ f1(v,w) - Σf1(u,v) 若存在可行流,0<=f1(u,v)<=c(u,v)-b(u,v),且保证下界流流满. 可以加超级源S,超级汇T. 假定某条边(u,v)的流量限制是[b,c],等价于S→v流

[BZOJ2502]清理雪道 有上下界网络流(最小流)

2502: 清理雪道 Time Limit: 10 Sec  Memory Limit: 128 MB Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部.从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道. 由于每次飞行的耗费是固定的,为了最小化耗费

hdu 4940 Destroy Transportation system( 无源汇上下界网络流的可行流推断 )

题意:有n个点和m条有向边构成的网络.每条边有两个花费: d:毁坏这条边的花费 b:重建一条双向边的花费 寻找这样两个点集,使得点集s到点集t满足 毁坏全部S到T的路径的费用和 > 毁坏全部T到S的路径的费用和 + 重建这些T到S的双向路径的费用和. 思路1: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center&quo