zoukankan      html  css  js  c++  java
  • 算法笔记--最大流和最小割 && 最小费用最大流 && 上下界网络流

    最大流:

    给定指定的一个有向图,其中有两个特殊的点源S(Sources)和汇T(Sinks),每条边有指定的容量(Capacity),求满足条件的从S到T的最大流(MaxFlow)。

    最小割:

    割是网络中定点的一个划分,它把网络中的所有顶点划分成两个顶点集合S和T,其中源点s∈S,汇点t∈T,从S出发指向T的边的集合,称为割(S,T),这些边的容量之和称为割的容量。容量最小的割称为最小割。

    根据最大流最小割定理,最大流等于最小割。

    其他:

    求最小割边的个数的方法:

    ①建边的时候每条边权 w = w * (E + 1) + 1;这样得到最大流 maxflow / (E + 1) ,最少割边数 maxflow % (E + 1)

    ②建图,得到最大流后,图中边若满流,说明该边是最小割上的边;再建图,原则:满流的边改为容量为 1 的边,未满流的边改为容量 INF 的边,然后最大流即答案

    Ford-Fulkerson算法模板:

    const int INF = 0x7f7f7f7f;
    struct edge {
        int to, w, rev;
    };
    vector<edge> g[N];
    bool vis[555];
    void add_edge(int from, int to, int w) {
        g[from].pb((edge){to, w, g[to].size()});
        g[to].pb((edge){from, 0, g[from].size()-1});
    }
    //通过dfs寻找增广路
    int dfs(int u, int t,int f) {
        if (u == t) return f;
        vis[u] = true;
        for (int i = 0; i < g[u].size(); i++) {
            edge &e = g[u][i];
            if(!vis[e.to] && e.w > 0) {
                int d = dfs(e.to, t, min(f, e.w));
                if(d > 0) {
                    e.w -= d;
                    g[e.to][e.rev].w += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int max_flow(int s, int t) {
        int flow = 0;
        while(true) {
            mem(vis, false);
            int f = dfs(s, t, INF);
            if (f == 0) return flow;
            flow += f;
        }
        return flow;
    }

    Dinic算法+弧优化模板:

    const int INF = 0x7f7f7f7f;
    int level[N], iter[N]; 
    struct edge {
        int to, w, rev;
    };
    vector<edge>g[N];
    void add_edge(int u, int v, int w) {
        g[u].pb(edge{v, w, g[v].size()});
        g[v].pb(edge{u, 0, g[u].size()-1});
    }  
    void bfs(int s) {
        mem(level, -1);
        queue<int>q;
        level[s] = 0;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < g[u].size(); i++) {
                edge e = g[u][i];
                if(e.w > 0 && level[e.to] < 0) {
                    level[e.to] = level[u] + 1;
                    q.push(e.to);
                    
                }
            }
        }
    }
    int dfs(int u, int t, int f) {
        if(u == t ) return f;
        for (int &i = iter[u]; i < g[u].size(); i++) {
            edge &e = g[u][i];
            if(e.w > 0 && level[u] < level[e.to]) {
                int d = dfs(e.to, t, min(f, e.w));
                if(d > 0) {
                    e.w -= d;
                    g[e.to][e.rev].w +=d;
                    return d;    
                }
            }
        } 
        return 0;
    } 
    int max_flow(int s, int t) {
        int flow = 0;
        while(true) {
            bfs(s);
            if(level[t] < 0) return flow;
            int f;
            mem(iter, 0);
            while ((f = dfs(s, t, INF)) > 0) {
                flow += f;
            }
        }
    }

    POJ 3281

    建图:把每头牛拆成两个,然后之间建一条容量为1的边,然后把food和drink分别放在牛的两边,分别和牛建容量为1的边,然后再在food和drink左右两边分别加一个源点s和汇点t。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<algorithm>
    using namespace std;
    #define LL long long
    #define pb push_back
    #define mem(a, b) memset(a, b, sizeof(a))
    
    const int N = 1555;
    const int INF = 0x7f7f7f7f;
    struct edge {
        int to, w, rev;
    };
    vector<edge> g[N];
    bool vis[555];
    void add_edge(int from, int to, int w) {
        g[from].pb((edge){to, w, g[to].size()});
        g[to].pb((edge){from, 0, g[from].size()-1});
    }
    int dfs(int u, int t,int f) {
        if (u == t) return f;
        vis[u] = true;
        for (int i = 0; i < g[u].size(); i++) {
            edge &e = g[u][i];
            if(!vis[e.to] && e.w > 0) {
                int d = dfs(e.to, t, min(f, e.w));
                if(d > 0) {
                    e.w -= d;
                    g[e.to][e.rev].w += d;
                    return d;
                }
            }
        }
        return 0;
    }
    int max_flow(int s, int t) {
        int flow = 0;
        while(true) {
            mem(vis, false);
            int f = dfs(s, t, INF);
            if (f == 0) return flow;
            flow += f;
        }
        return flow;
    }
    int main() {
        int n, f, d, t, _t, u;
        scanf("%d%d%d", &n, &f, &d);
        for (int i = 1; i <= n; i++) {
            add_edge(i, i+n, 1);
        }
        for (int i = 1; i <= n; i++) {
            scanf("%d%d", &t, &_t);
            while(t--) {
                scanf("%d", &u);
                add_edge(u+2*n, i, 1);
            }
            while(_t--) {
                scanf("%d", &u);
                add_edge(i+n, u+2*n+f, 1);
            }
        }
        for (int i = 1; i <= f; i++) {
            add_edge(0, i+2*n, 1);
        }
        for (int i = 1; i <= d; i++) {
            add_edge(i+2*n+f, 500, 1);
        }
        printf("%d
    ", max_flow(0, 500));
        return 0;
    }
    View Code

     POJ 3436

    建图:把每台设备拆成两个,然后之间建一条容量为设备操作台数的边,然后在所有的input里找没有1的设备,与源点s相连,在所有的output里找没有0的设备,与汇点t相连。然后设备之间如果input和output能匹配,就相连。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<algorithm>
    using namespace std;
    #define LL long long 
    #define pb push_back
    #define mem(a, b) memset(a, b, sizeof(a))
    
    const int N = 66;
    const int INF = 0x7f7f7f7f;
    int level[N*2], iter[N*2], in[N][15], out[N][15]; 
    bool vis[N][N];
    struct edge {
        int to, w, rev;
    };
    struct node {
        int x, y, z;
    }res[N*N];
    vector<edge>g[N*2];
    void add_edge(int u, int v, int w) {
        g[u].pb(edge{v, w, g[v].size()});
        g[v].pb(edge{u, 0, g[u].size()-1});
    }  
    void bfs(int s) {
        mem(level, -1);
        queue<int>q;
        level[s] = 0;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int i = 0; i < g[u].size(); i++) {
                edge e = g[u][i];
                if(e.w > 0 && level[e.to] < 0) {
                    level[e.to] = level[u] + 1;
                    q.push(e.to);
                    
                }
            }
        }
    }
    int dfs(int u, int t, int f) {
        if(u == t ) return f;
        for (int &i = iter[u]; i < g[u].size(); i++) {
            edge &e = g[u][i];
            if(e.w > 0 && level[u] < level[e.to]) {
                int d = dfs(e.to, t, min(f, e.w));
                if(d > 0) {
                    e.w -= d;
                    g[e.to][e.rev].w +=d;
                    return d;    
                }
            }
        } 
        return 0;
    } 
    int max_flow(int s, int t) {
        int flow = 0;
        while(true) {
            bfs(s);
            if(level[t] < 0) return flow;
            int f;
            mem(iter, 0);
            while ((f = dfs(s, t, INF)) > 0) {
                flow += f;
            }
        }
    }
    int main() {
        int p, n, w;
        while(~ scanf("%d%d", &p, &n)) {
            for (int i = 0; i < N*2; i++) g[i].clear();
            mem(vis, false);
            for (int i = 1; i <= n; i++) {
                scanf("%d", &w);
                add_edge(i, i+n, w);
                for (int j = 1; j <= p; j++) scanf("%d", &in[i][j]);
                for (int j = 1; j <= p; j++) scanf("%d", &out[i][j]);
            } 
            for (int i = 1; i <= n; i++) {
                bool f = true, _f = true;
                for (int j = 1; j <= p; j++) if(in[i][j] == 1) f = false;
                for (int j = 1; j <= p; j++) if(!out[i][j]) _f = false;
                if(f) add_edge(0, i, INF);
                if(_f) add_edge(i+n, 120, INF);
                for (int j = i + 1; j <= n; j++) {
                    bool f = true, _f = true;
                    for (int k = 1; k <= p; k++) {
                        if(in[j][k] == 2);
                        else {
                            if(out[i][k] != in[j][k]) f = false;
                        }
                        if(in[i][k] == 2);
                        else {
                            if(out[j][k] != in[i][k]) _f = false;
                        }
                    }
                    if(f) add_edge(i+n, j, INF), vis[i][j] = true;
                    if(_f) add_edge(j+n, i, INF), vis[j][i] = true;
                }
            }
            int ans = max_flow(0, 120);
            int cnt = 0;
            for (int i = 1; i <= n; i++) {
                if(g[i].size() == 0)continue;
                for (int j = 0; j < g[i].size(); j++) {
                    if(g[i][j].to == 0 || g[i][j].to == 120 || g[i][j].to == i+n || g[i][j].to <= n ) continue;
                    if(0 < g[i][j].w && vis[g[i][j].to-n][i]) {
                        res[++cnt].x = g[i][j].to - n;
                        res[cnt].y = i;
                        res[cnt].z = g[i][j].w;
                    }
                }
            }
            printf("%d %d
    ", ans, cnt);
            for (int i = 1; i <= cnt; i++) printf("%d %d %d
    ", res[i].x, res[i].y, res[i].z);
        }
        return 0;
    } 
    View Code

    最小费用最大流:

    详见挑战程序设计

    上下界网络流: 

    https://www.cnblogs.com/NineSwords/p/9415962.html

  • 相关阅读:
    The last access date is not changed even after reading the file on Windows 7
    渗透基础——获得当前系统已安装的程序列表
    Top 10 Best Free Netflow Analyzers and Collectors for Windows
    平安科技移动开发二队技术周报(第十五期)
    Intent传递对象的几种方式
    SQLite基础学习
    2 Java基础语法(keyword,标识符,凝视,常量,进制转换,变量,数据类型,数据类型转换)
    iOS 之应用性能调优的25个建议和技巧
    Fragment事务管理源代码分析
    CMake
  • 原文地址:https://www.cnblogs.com/widsom/p/8953868.html
Copyright © 2011-2022 走看看