• 网络流算法模板


      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;
    }
  • 相关阅读:
    计算机 ------- 网络基础
    设计模式------单例模式
    svn 客户端查看用户名和密码
    Docker:DockerFile(DockerFile解析)
    Docker:容器数据卷(命令方式、DockerFile方式)
    SpringBoot再总结
    Docker:镜像(镜像原理)
    Docker:Docker命令(帮助命令、镜像命令、容器命令)
    Docker(Docker的概念与安装)
    ZooKeeper:zookeeper的常用命令(节点的新增、更新、删除)
  • 原文地址:https://www.cnblogs.com/vongang/p/2360518.html
Copyright © 2020-2023  润新知