网络流算法模板

  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;
}
原文地址:https://www.cnblogs.com/vongang/p/2360518.html