首页 > 技术文章 > [POJ1273]Drainage Ditches 网络流(最大流)

kirai 2015-11-13 11:31 原文

题目链接:http://poj.org/problem?id=1273

  网络流裸题,注意有重边。重边的处理方法很简单,就是将对应的c叠加到对应边上。注意初始化为0。

  我用的是最朴素的FF方法,即找增广路。之前用dfs找增广路WA了,应该是碰到了随机找一条增光路这种方法碰到了killer case。给出WA代码(初学用喜闻乐见链式前向星建图,比较繁琐。不过好在最终还是WA掉了)。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 typedef struct Edge {
23     int v;
24     int c;
25     int next;
26     Edge() { next = -1; }
27 }Edge;
28 
29 const int maxn = 222;
30 int n, m, s, t;
31 int head[maxn];
32 int vis[maxn];
33 int cnt = 0;
34 Edge edge[maxn<<1];
35 
36 void init() {
37     memset(head, -1, sizeof(head));
38     memset(vis, 0, sizeof(vis));
39     cnt = 0;
40 }
41 
42 void adde(int u, int v, int c) {
43     edge[cnt].v = v; edge[cnt].next = head[u];
44     edge[cnt].c = c; head[u] = cnt++;
45     edge[cnt].v = v; edge[cnt].next = head[u];
46     edge[cnt].c = 0; head[v] = cnt++;
47 }
48 
49 int dfs(int v, int f) {
50     if(v == t) return f;
51     vis[v] = 1;
52     for(int i = head[v]; ~i; i = edge[i].next) {
53         if(!vis[edge[i].v] && edge[i].c > 0) {
54             int d = dfs(edge[i].v, min(f, edge[i].c));
55             if(d > 0) {
56                 edge[i].c -= d;
57                 edge[i+1].c += d;
58                 return d;
59             }
60         }
61     }
62     return 0;
63 }
64 
65 int max_flow() {
66     int flow = 0;
67     while(1) {
68         memset(vis, 0, sizeof(vis));
69         int tf = dfs(s, 2147483647);
70         if(tf == 0) return flow;
71         flow += tf;
72     }
73     return flow;
74 }
75 
76 int main() {
77     // freopen("in", "r", stdin);
78     int u, v, c;
79     while(~scanf("%d %d", &m, &n)) {
80         init();
81         for(int i = 0; i < m; i++) {
82             scanf("%d %d %d", &u, &v, &c);
83             adde(u, v, c);
84         }
85         s = 1;
86         t = n;
87         printf("%d\n", max_flow());
88     }
89     return 0;
90 }

 

  随后索性全部删掉一切从简,改用最简单的邻接矩阵。利用BFS,第一次接触到汇点的那条路径一定是最短的(因为BFS是层进的)。找到了这条路并且记录下来即可。

接着,从源向外发出一个流(一定要足够大),按照之前BFS到的最短增广路流向汇点,根据短板效应找到流量,更新到最大流量上之后再更新残余网络(直接在原网络上更新即可)。下图可以比较清晰地说明这一点:

简要证明:

  我们从右图化简它的过程以及路径得到了右图。假设图中的源点可由b流经a到达汇点,而且假设b->a在当前所找到的增广路上,表示为G[b][a]。再假设该路上的流量为k,容量为n,那么当前b->a上的流量应被修改为k,且该路径在残余网络上残余的容量是n-k。而残余网络上,该路径表示为G[a][b]。如左图所示,对这两条路进行了一次合并,那么规定原图上初始流向为正方向,那么当前网络和残余网络上该路上的流量应当是n+(-(n-k))=n-n+k=k。因此只需要对两部分更新流量k就好了。在代码中,b相当于a的前驱点,也就是pre[a]。那么我们更新残余网络上对应的路的时候(也就是更新G[a][pre[a]]),相当于+k,而更新原图(G[pre[a]][a])的时候,相当于-k。

代码如下:

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <bitset>
11 #include <vector>
12 #include <deque>
13 #include <queue>
14 #include <stack>
15 #include <ctime>
16 #include <set>
17 #include <map>
18 #include <cmath>
19 
20 using namespace std;
21 
22 const int inf = 0x7fffff;
23 const int maxn = 222;
24 int G[maxn][maxn];
25 int pre[maxn];
26 int vis[maxn];
27 int m, n, s, t;
28 
29 void init() {
30     memset(G, 0, sizeof(G));
31     memset(pre, 0, sizeof(pre));
32     memset(vis, 0, sizeof(vis));
33 }
34 
35 bool bfs() {
36     memset(vis, 0, sizeof(vis));
37     memset(pre, 0, sizeof(pre));
38     queue<int> q;
39     q.push(s);
40     vis[s] = 1;
41     while(!q.empty()) {
42         int v = q.front(); q.pop();
43         for(int i = 1; i <= n; i++) {
44             if(G[v][i] > 0 && !vis[i]) {
45                 q.push(i);
46                 vis[i] = 1;
47                 pre[i] = v;
48                 if(i == n) {
49                     return 1;
50                 }
51             }
52         }
53     }
54     return 0;
55 }
56 
57 int max_flow() {
58     int flow = 0;
59     while(1) {
60         if(!bfs()) return flow;
61         int v = n;
62         int k = inf;
63         while(pre[v]) {
64             k = min(k, G[pre[v]][v]);
65             v = pre[v];
66         }
67         v = n;
68         flow += k;
69         while(pre[v]) {
70             G[v][pre[v]] += k;
71             G[pre[v]][v] -= k;
72             v = pre[v];
73         }
74     }
75     return flow;
76 }
77 
78 int main() {
79     // freopen("in", "r", stdin);
80     int u, v, c;
81     while(~scanf("%d %d", &m, &n)) {
82         init();
83         for(int i = 0; i < m; i++) {
84             scanf("%d %d %d", &u, &v, &c);
85             G[u][v] += c;
86         }
87         s = 1; t = n;
88         printf("%d\n", max_flow());
89     }
90 }

 

dinic板子

  1 /*
  2 ━━━━━┒ギリギリ♂ eye!
  3 ┓┏┓┏┓┃キリキリ♂ mind!
  4 ┛┗┛┗┛┃\○/
  5 ┓┏┓┏┓┃ /
  6 ┛┗┛┗┛┃ノ)
  7 ┓┏┓┏┓┃
  8 ┛┗┛┗┛┃
  9 ┓┏┓┏┓┃
 10 ┛┗┛┗┛┃
 11 ┓┏┓┏┓┃
 12 ┛┗┛┗┛┃
 13 ┓┏┓┏┓┃
 14 ┃┃┃┃┃┃
 15 ┻┻┻┻┻┻
 16 */
 17 #include <algorithm>
 18 #include <iostream>
 19 #include <iomanip>
 20 #include <cstring>
 21 #include <climits>
 22 #include <complex>
 23 #include <fstream>
 24 #include <cassert>
 25 #include <cstdio>
 26 #include <bitset>
 27 #include <vector>
 28 #include <deque>
 29 #include <queue>
 30 #include <stack>
 31 #include <ctime>
 32 #include <set>
 33 #include <map>
 34 #include <cmath>
 35 using namespace std;
 36 #define fr first
 37 #define sc second
 38 #define cl clear
 39 #define BUG puts("here!!!")
 40 #define W(a) while(a--)
 41 #define pb(a) push_back(a)
 42 #define Rint(a) scanf("%d", &a)
 43 #define Rs(a) scanf("%s", a)
 44 #define Cin(a) cin >> a
 45 #define FRead() freopen("in", "r", stdin)
 46 #define FWrite() freopen("out", "w", stdout)
 47 #define Rep(i, len) for(int i = 0; i < (len); i++)
 48 #define For(i, a, len) for(int i = (a); i < (len); i++)
 49 #define Cls(a) memset((a), 0, sizeof(a))
 50 #define Clr(a, x) memset((a), (x), sizeof(a))
 51 #define Full(a) memset((a), 0x7f7f7f, sizeof(a))
 52 #define lrt rt << 1
 53 #define rrt rt << 1 | 1
 54 #define pi 3.14159265359
 55 #define RT return
 56 #define lowbit(x) x & (-x)
 57 #define onecnt(x) __builtin_popcount(x)
 58 typedef long long LL;
 59 typedef long double LD;
 60 typedef unsigned long long ULL;
 61 typedef pair<int, int> pii;
 62 typedef pair<string, int> psi;
 63 typedef pair<LL, LL> pll;
 64 typedef map<string, int> msi;
 65 typedef vector<int> vi;
 66 typedef vector<LL> vl;
 67 typedef vector<vl> vvl;
 68 typedef vector<bool> vb;
 69 
 70 typedef struct Edge {
 71     int u, v, c, next;
 72 }Edge;
 73 
 74 const int inf = 0x7f7f7f7f;
 75 const int maxn = 220;
 76 
 77 int cnt, head[maxn];
 78 int cur[maxn], dd[maxn];
 79 Edge edge[maxn*maxn*2];
 80 int N, S, T;
 81 
 82 void init() {
 83     memset(head, -1, sizeof(head));
 84     for(int i = 0; i < maxn; i++) edge[i].next = -1;
 85 }
 86 
 87 void adde(int u, int v, int c, int c1) {
 88     edge[cnt].u = u; edge[cnt].v = v; edge[cnt].c = c; 
 89     edge[cnt].next = head[u]; head[u] = cnt++;
 90     edge[cnt].u = v; edge[cnt].v = u; edge[cnt].c = c1; 
 91     edge[cnt].next = head[v]; head[v] = cnt++;
 92 }
 93 
 94 bool bfs(int s, int t, int n) {
 95     queue<int> q;
 96     for(int i = 0; i < n; i++) dd[i] = inf;
 97     dd[s] = 0;
 98     q.push(s);
 99     while(!q.empty()) {
100         int u = q.front(); q.pop();
101         for(int i = head[u]; ~i; i = edge[i].next) {
102             if(dd[edge[i].v] > dd[u] + 1 && edge[i].c > 0) {
103                 dd[edge[i].v] = dd[u] + 1;
104                 if(edge[i].v == t) return 1;
105                 q.push(edge[i].v);
106             }
107         }
108     }
109     return 0;
110 }
111 
112 int dinic(int s, int t, int n) {
113     int st[maxn], top;
114     int u;
115     int flow = 0;
116     while(bfs(s, t, n)) {
117         for(int i = 0; i < n; i++) cur[i] = head[i];
118         u = s; top = 0;
119         while(cur[s] != -1) {
120             if(u == t) {
121                 int tp = inf;
122                 for(int i = top - 1; i >= 0; i--) {
123                     tp = min(tp, edge[st[i]].c);
124                 }
125                 flow += tp;
126                 for(int i = top - 1; i >= 0; i--) {
127                     edge[st[i]].c -= tp;
128                     edge[st[i] ^ 1].c += tp;
129                     if(edge[st[i]].c == 0) top = i;
130                 }
131                 u = edge[st[top]].u;
132             }
133             else if(cur[u] != -1 && edge[cur[u]].c > 0 && dd[u] + 1 == dd[edge[cur[u]].v]) {
134                 st[top++] = cur[u];
135                 u = edge[cur[u]].v;
136             }
137             else {
138                 while(u != s && cur[u] == -1) {
139                     u = edge[st[--top]].u;
140                 }
141                 cur[u] = edge[cur[u]].next;
142             }
143         }
144     }
145     return flow;
146 }
147 
148 int n, m;
149 int G[maxn][maxn];
150 
151 int main() {
152     // FRead();
153     int u, v, w;
154     while(~Rint(m) && ~Rint(n)) {
155         Cls(G); S = 0, N = n, T = n - 1; init();
156         Rep(i, m) {
157             Rint(u); Rint(v); Rint(w);
158             G[u-1][v-1] += w;
159         }
160         Rep(i, n) {
161             Rep(j, n) {
162                 if(G[i][j] != 0) adde(i, j, G[i][j], 0);
163             }
164         }
165         printf("%d\n", dinic(S, T, N));
166     }
167     RT 0;
168 }
Dinic

 

推荐阅读