[POJ1273]Drainage Ditches 网络流(最大流)
题目链接: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 }