1、基于Ford-Fulkerson方法的Edmonds-Karp算法
用广度有限搜索来实现对增广路径p 的计算。即,如果增广路径是残留网络种从s 到t 的最短路径,则能够改进Ford-Fulkerson的界。
View Code
1 //做一次增广路径的流量统计
2
3 int augment() {
4 int v, i, ans;
5 bool flag = false;
6 deque<int> q;
7
8 memset(vis, 0, sizeof(vis));
9 memset(pre, -1, sizeof(pre));
10
11 q.push_back(0);
12 vis[0] = true;
13 pre[0] = -1;
14
15 while(!q.empty()) {
16 v = q.front();
17 q.pop_front();
18
19 for(i = 0; i <= n; i++) {
20 if(g[v][i] > 0 && !vis[i]) {
21 vis[i] = true;
22 pre[i] = v;
23 if(i == n) {
24 flag = true;
25 q.clear();
26 break;
27 } else {
28 q.push_back(i);
29 }
30 }
31 }
32 }
33 if(!flag) return 0;
34 v = n; ans = inf;
35 while(pre[v] != -1) {
36 ans = min(ans, g[pre[v]][v]);
37 v = pre[v];
38 }
39 v = n;
40 while(pre[v] != -1) {
41 g[pre[v]][v] -= ans;
42 g[v][pre[v]] += ans;
43 v = pre[v];
44 }
45 return ans;
46 }
2、Dinic算法
详细讲解:http://en.wikipedia.org/wiki/Dinic's_algorithm
其实就是对原来的流网络用bfs进行分层,找到一条增广路径后退到节点pos,节点pos满足 f(pos, pos->next) = c(pos, pos->next);然后再进行bfs找经过pos的其他增广路径。
View Code
1 int g[N][N];
2 int layer[N];
3 bool vis[N];
4
5 int S, T;
6
7 bool Layer() { //分层次
8 deque<int> q;
9 memset(layer, -1, sizeof(layer));
10 q.push_back(0);
11 layer[0] = 1;
12 int i, v;
13 while(!q.empty()) {
14 v = q.front();
15 q.pop_front();
16 for(i = 0; i <= T; i++) {
17 if(g[v][i] > 0 && layer[i] == -1) {
18 //printf("%d %d\n", v, i);
19 layer[i] = layer[v] + 1;
20 if(i == T) {q.clear(); return true;}
21 else q.push_back(i);
22 }
23 }
24 }
25 return false;
26 }
27
28 int Dinic() {
29 deque<int> q;
30 int i, v, vs, vt, MIN, pos, sum = 0;
31
32 while(Layer()) {
33 memset(vis, 0, sizeof(vis));
34 q.push_back(0);
35 vis[0] = true;
36
37 while(!q.empty()) {
38 v = q.back();
39 if(v == T) {
40 MIN = inf;
41 for(i = 1; i < q.size(); i++) {
42 vs = q[i-1]; vt = q[i];
43 if(g[vs][vt] > 0 && g[vs][vt] < MIN) {
44 MIN = g[vs][vt];
45 pos = vs;
46 }
47 }
48 sum += MIN;
49 for(i = 1; i < q.size(); i++) {
50 vs = q[i-1]; vt = q[i];
51 if(g[vs][vt] > 0) {
52 g[vs][vt] -= MIN;
53 g[vt][vs] += MIN;
54 }
55 }
56 while(!q.empty() && q.back() != pos) { //退回到pos再找其他增广路径
57 vis[q.back()] = false;
58 q.pop_back();
59 }
60 } else {
61 for(i = 0; i <= T; i++) {
62 if(g[v][i] > 0 && !vis[i] && layer[i] == layer[v] + 1) {
63 vis[i] = true;
64 q.push_back(i);
65 break;
66 }
67 }
68 if(i > T) q.pop_back();
69 }
70 }
71 }
72 return sum;
73 }
Dinic算法邻接表实现,很强大的模板。
View Code
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #define REP(i, n) for(i = 0; i < n; ++i) #define FOR(i, l, h) for(i = l; i <= h; ++i) #define FORD(i, h, l) for(i = h; i >= l; --i) #define CL(arr, val) memset(arr, val, sizeof(arr)) using namespace std; const int N = 3000; const double inf = ~0u; struct node { int to; double val; int next; } g[N*N]; int head[N], t; int layer[N]; int q[N*1000]; int S, T; void init() { CL(head, -1); t = 0; } void add(int u, int v, double c) { g[t].to = v; g[t].val = c; g[t].next = head[u]; head[u] = t++; g[t].to = u; g[t].val = 0; g[t].next = head[v]; head[v] = t++; } bool Layer() { //分层 CL(layer, -1); int f = 0, r = 0, i, u, v; q[r++] = S; layer[S] = 1; while(f < r) { u = q[f++]; for(i = head[u]; i != -1; i = g[i].next) { v = g[i].to; if(g[i].val > 0 && layer[v] == -1) { layer[v] = layer[u] + 1; if(v == T) return true; q[r++] = v; } } } return false; } double find() { //找一次增广路 int u, i, e, pos, top; double sum = 0, flow; top = 1; while(top) { u = (top == 1 ? S : g[q[top-1]].to); if(u == T) { flow = inf; FOR(i, 1, top - 1) { e = q[i]; if(g[e].val < flow) { flow = g[e].val; pos = i; } } FOR(i, 1, top - 1) { e = q[i]; g[e].val -= flow; g[e^1].val += flow; } sum += flow; top = pos; } else { for(i = head[u]; i != -1; i = g[i].next) { if(g[i].val > 0 && layer[g[i].to] == layer[u] + 1) break; } if(i != -1) q[top++] = i; else { --top; layer[u] = -1; } } } return sum; } double Dinic() { double res = 0; while(Layer()) res += find(); return res; } int main() { //freopen("data.in", "r", stdin); int t, n, m, l; int i, u, v; double val; scanf("%d", &t); while(t--) { init(); scanf("%d%d%d", &n, &m, &l); S = 0; T = n + m + 1; FOR(i, 1, n) { scanf("%lf", &val); add(S, i, log(val)); } FOR(i, 1, m) { scanf("%lf", &val); add(i + n, T, log(val)); } while(l--) { scanf("%d%d", &u, &v); add(u, v + n, inf); } printf("%.4lf\n", exp(Dinic())); } return 0; }