• 网络流应用(一)


    无源汇上下界可行流

    题目:

    给定一个包含 n 个点 m 条边的有向图,每条边都有一个流量下界和流量上界。

    求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。

    code

    #include
    using namespace std;
    const int N = 210, M = (10200 + N) * 2;
    const int INF = 1e8;
    int n, m, S, T;
    int A[N];

    int e[M], f[M], l[M], ne[M], h[M], idx;
    void add(int u, int v, int c, int d){
        e[idx] = v, f[idx] = d - c, l[idx] = c, ne[idx] = h[u], h[u] = idx++;
        e[idx] = u, f[idx] = 0, ne[idx] = h[v], h[v] = idx++;
    }

    int q[N], cur[N], d[N];
    bool bfs(){
        int hh = 0, tt = 0;
        memset(d, -1, sizeof d);
        q[0] = S, cur[S] = h[S], d[S] = 0;
        while(hh <= tt){
            int u = q[hh++];
            for(int i = h[u]; ~i; i = ne[i]){
                int v = e[i];
                if(d[v] == -1 && f[i]){
                    d[v] = d[u] + 1;
                    cur[v] = h[v];
                    if(v == T) return true;
                    q[++tt] = v;
                }
            }
        }
        return false;
    }

    int find(int u, int limit){
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && flow < limit; i = ne[i]){
            cur[u] = i;
            int v = e[i];
            if(d[v] == d[u] + 1 && f[i]){
                int t = find(v, min(f[i], limit - flow));
                if(!t) d[v] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }

    int dinic(){
        int res = 0, flow;
        while(bfs()) while(flow = find(S, INF)) res += flow;
        return res;
    }

    int main(){
        memset(h, -1, sizeof h);
        scanf("%d%d", &n, &m);
        S = 0, T = n + 1;
        for(int i = 1; i <= m; i++){
            int a, b, c, d;
            scanf("%d%d%d%d", &a, &b, &c, &d); // a 到 b 之间有边,下界为c,上界为d
            add(a, b, c, d);
            A[a] -= c, A[b] += c;
        }
        int tot = 0;
        for(int i = 1; i <= n; i++){
            if(A[i] > 0) add(S, i, 0, A[i]), tot += A[i];
            else if(A[i] < 0) add(i, T, 0, -A[i]);
        }
        if(tot == dinic()){
            puts("YES");
            for(int i = 0; i < 2 * m; i += 2){
                if(e[i] >= 1 && e[i] <= n){
                    printf("%d\n", f[i ^ 1] + l[i]);
                }
            }
        }
        else puts("NO");
        return 0;
    }

    有源汇上下界最大流

    题目:

    给定一个包含 nn 个点 mm 条边的有向图,每条边都有一个流量下界和流量上界。

    给定源点 SS 和汇点 TT,求源点到汇点的最大流。

    code

    【s、t:题目给出的源点和汇点, S、T:虚拟源点和汇点】
    const int N = 220, M = (1e4 + N + 20) * 2;
    const int INF = 1e8;
    int n, m, s, t, S, T;
    int A[N];

    int e[M], f[M], ne[M], h[M], idx;
    void add(int u, int v, int c){
        e[idx] = v, f[idx] = c, ne[idx] = h[u], h[u] = idx++;
        e[idx] = u, f[idx] = 0, ne[idx] = h[v], h[v] = idx++;
    }

    int q[N], cur[N], d[N];
    bool bfs(){
        int hh = 0, tt = 0;
        memset(d, -1, sizeof d);
        q[0] = S, cur[S] = h[S], d[S] = 0;
        while(hh <= tt){
            int u = q[hh++];
            for(int i = h[u]; ~i; i = ne[i]){
                int v = e[i];
                if(d[v] == -1 && f[i]){
                    d[v] = d[u] + 1;
                    cur[v] = h[v];
                    if(v == T) return true;
                    q[++tt] = v;
                }
            }
        }
        return false;
    }

    int find(int u, int limit){
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && flow < limit; i = ne[i]){
            cur[u] = i;
            int v = e[i];
            if(d[v] == d[u] + 1 && f[i]){
                int t = find(v, min(f[i], limit - flow));
                if(!t) d[v] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }

    int dinic(){
        int res = 0, flow;
        while(bfs()) while(flow = find(S, INF)) res += flow;
        return res;
    }

    int main(){
        memset(h, -1, sizeof h);
        scanf("%d%d%d%d", &n, &m, &s, &t);
        S = 0, T = n + 1;
        for(int i = 1; i <= m; i++){
            int a, b, c, d;
            scanf("%d%d%d%d", &a, &b, &c, &d);
            add(a, b, d - c);
            A[a] -= c, A[b] += c;
        }
        int tot = 0;
        for(int i = 1; i <= n; i++){
            if(A[i] > 0) add(S, i, A[i]), tot += A[i];
            else if(A[i] < 0) add(i, T, -A[i]);
        }
        add(t, s, INF);
        if(tot == dinic()){
            S = s, T = t;
            int res = f[idx - 1];
            f[idx - 1] = 0, f[idx - 2] = 0;
            printf("%d\n", res + dinic());
        }
        else puts("No Solution");
        return 0;
    }

    有源汇上下界最小流

    题目:

    给定一个包含 nn 个点 mm 条边的有向图,每条边都有一个流量下界和流量上界。

    给定源点 SS 和汇点 TT,求源点到汇点的最小流。

    注意,为了方便,本题做出如下约定:

    • 可行流流量 = 从源点流出的流量 - 流入源点的流量,可以为负值。
    • 例如,当 S→TS→T 的流量为 00,T→ST→S 的流量为 1010 时,S→TS→T 的流量为 −10−10。

    code

    const int N = 50010, M = (125003  + N + 20) * 2;
    const int INF = 1e8;
    int n, m, s, t, S, T;
    int A[N];

    int e[M], f[M], ne[M], h[M], idx;
    void add(int u, int v, int c){
        e[idx] = v, f[idx] = c, ne[idx] = h[u], h[u] = idx++;
        e[idx] = u, f[idx] = 0, ne[idx] = h[v], h[v] = idx++;
    }

    int q[N], cur[N], d[N];
    bool bfs(){
        int hh = 0, tt = 0;
        memset(d, -1, sizeof d);
        q[0] = S, cur[S] = h[S], d[S] = 0;
        while(hh <= tt){
            int u = q[hh++];
            for(int i = h[u]; ~i; i = ne[i]){
                int v = e[i];
                if(d[v] == -1 && f[i]){
                    d[v] = d[u] + 1;
                    cur[v] = h[v];
                    if(v == T) return true;
                    q[++tt] = v;
                }
            }
        }
        return false;
    }

    int find(int u, int limit){
        if(u == T) return limit;
        int flow = 0;
        for(int i = cur[u]; ~i && flow < limit; i = ne[i]){
            cur[u] = i;
            int v = e[i];
            if(d[v] == d[u] + 1 && f[i]){
                int t = find(v, min(f[i], limit - flow));
                if(!t) d[v] = -1;
                f[i] -= t, f[i ^ 1] += t, flow += t;
            }
        }
        return flow;
    }

    int dinic(){
        int res = 0, flow;
        while(bfs()) while(flow = find(S, INF)) res += flow;
        return res;
    }

    int main(){
        memset(h, -1, sizeof h);
        scanf("%d%d%d%d", &n, &m, &s, &t);
        S = 0, T = n + 1;
        for(int i = 1; i <= m; i++){
            int a, b, c, d;
            scanf("%d%d%d%d", &a, &b, &c, &d);
            add(a, b, d - c);
            A[a] -= c, A[b] += c;
        }
        int tot = 0;
        for(int i = 1; i <= n; i++){
            if(A[i] > 0) add(S, i, A[i]), tot += A[i];
            else if(A[i] < 0) add(i, T, -A[i]);
        }
        add(t, s, INF);
        if(tot == dinic()){
            S = t, T = s;
            int res = f[idx - 1];
            f[idx - 1] = 0, f[idx - 2] = 0;
            printf("%d\n", res - dinic());
        }
        else puts("No Solution");
        return 0;
    }

    多源汇最大流

    建S、T,从S到每个s连一条INF的边,每个t到T连一条INF的边(代码就不放了,套模板)

  • 相关阅读:
    SUSE linux的软件管理工具-zypper
    设计模式:责任链模式(C++实现)
    Android学习笔记 1.6 Android应用结构分析
    详解KubeEdge边缘网络项目EdgeMesh
    数学建模中所需要使用到的Matlab(从零开始介绍)
    vue重修004【下部】
    绘制X-Bar-S和X-Bar-R图,监测过程,计算CPK过程能力指数
    【SpringBoot自动装配之SPI机制&SPI案例实操学习&SPI机制核心源码学习】
    图象处理算法(介绍)
    手撕红黑树的插入(C++)
  • 原文地址:https://blog.csdn.net/Galaxy_Su/article/details/127554700