网络流模板大全

Posted xjr_01

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流模板大全相关的知识,希望对你有一定的参考价值。

说“大全”,其实也不见得全。。。

1、最大流,Dinic 模板。[LOJ#101]

这题 Dinic 需要卡常才能过,主要是 BFS 从汇点开始搜更快。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 1000010
#define maxm 8000010
#define oo 2147483647
#define LL long long

struct Edge {
    int from, to, flow;
    Edge() {}
    Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
};
struct Dinic {
    int n, m, s, t, head[maxn], nxt[maxm];
    Edge es[maxm];
    int vis[maxn], Q[maxn], hd, tl;
    int cur[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c) {
        es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS() {
        memset(vis, 0, sizeof(vis));
        vis[t] = 1;
        hd = tl = 0; Q[++tl] = t;
        while(hd < tl) {
            int u = Q[++hd];
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(!vis[e.from] && e.flow) {
                    vis[e.from] = vis[u] + 1;
                    Q[++tl] = e.from;
                }
            }
        }
        return vis[s] > 0;
    }
    
    LL DFS(int u, int a) {
        if(u == t || !a) return a;
        LL flow = 0, f;
        for(int& i = cur[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    LL MaxFlow(int _s, int _t) {
        s = _s; t = _t;
        LL flow = 0;
        while(BFS()) {
            rep(i, 1, n) cur[i] = head[i];
            flow += DFS(s, oo);
        }
        return flow;
    }
} sol;

int main() {
    int n = read(), m = read(), s = read(), t = read();
    sol.init();
    rep(i, 1, m) {
        int u = read(), v = read(), c = read();
        sol.AddEdge(u, v, c);
    }
    sol.setn(n);
    printf("%lld\n", sol.MaxFlow(s, t));
    
    return 0;
}

2、最小费用最大流,ZKW 模板。[LOJ#102]

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 410
#define maxm 30010
#define oo 2147483647

struct Edge {
    int from, to, flow, cost;
    Edge() {}
    Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
};
struct ZKW {
    int s, t, cost, ans, n, m, head[maxn], nxt[maxm];
    Edge es[maxm];
    int d[maxn];
    deque <int> Q;
    bool inq[maxn];
    bool vis[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c, int d) {
        es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS() {
        rep(i, 1, n) d[i] = oo;
        Q.push_back(t); inq[t] = 1;
        d[t] = 0;
        while(!Q.empty()) {
            int u = Q.front(); Q.pop_front(); inq[u] = 0;
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(d[e.from] > d[u] + e.cost && e.flow) {
                    d[e.from] = d[u] + e.cost;
                    if(!inq[e.from]) {
                        inq[e.from] = 1;
                        if(Q.empty() || d[Q.front()] >= d[e.from]) Q.push_front(e.from);
                        else Q.push_back(e.from);
                    }
                }
            }
        }
        if(d[s] == oo) return 0;
        cost = d[s];
        return 1;
    }
    
    int DFS(int u, int a) {
        if(u == t || !a){ ans += cost * a; return a; }
        if(vis[u]) return 0;
        vis[u] = 1;
        int flow = 0, f;
        for(int i = head[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(d[e.to] == d[u] - e.cost && e.flow && (f = DFS(e.to, min(e.flow, a)))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    int MaxFlow(int _s, int _t) {
        s = _s; t = _t;
        int flow = 0, f;
        while(BFS())
            do {
                memset(vis, 0, sizeof(vis));
                f = DFS(s, oo);
                flow += f;
            } while(f);
        return flow;
    }
} sol;

int main() {
    int n = read(), m = read();
    sol.init();
    rep(i, 1, m) {
        int a = read(), b = read(), c = read(), d = read();
        sol.AddEdge(a, b, c, d);
    }
    sol.setn(n);
    printf("%d ", sol.MaxFlow(1, n));
    printf("%d\n", sol.ans);
    
    return 0;
}

3、无源汇有上下界可行流。[LOJ#115]

先强行让每条边流成下界,那么现在可能有一些点出入不平衡, 需要调整。假设节点 \(u\) 出大于入,那么从 \(u\) 向新建汇点连一条出流 - 入流的边;假设节点 \(v\) 入大于出,那么从新建源点向 \(v\) 连一条入流 - 出流的边。(因为我们需要通过原图将流量调至平衡,所以出多反而需要连出边,入多需要连入边)

如果新图最大流不能把源点出发(或到达汇点)的流量流满,就说明无解。若有解,则最终每条边的流量 = 流量下界 + 新图中对应边的流量。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 210
#define maxm 61210
#define oo 2147483647

struct Edge {
    int from, to, flow;
    Edge() {}
    Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
};
struct Dinic {
    int n, m, s, t, head[maxn], nxt[maxm];
    Edge es[maxm];
    int vis[maxn], Q[maxn], hd, tl;
    int cur[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c) {
        es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS() {
        memset(vis, 0, sizeof(vis));
        vis[t] = 1;
        hd = tl = 0; Q[++tl] = t;
        while(hd < tl) {
            int u = Q[++hd];
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(!vis[e.from] && e.flow) {
                    vis[e.from] = vis[u] + 1;
                    Q[++tl] = e.from;
                }
            }
        }
        return vis[s] > 0;
    }
    
    int DFS(int u, int a) {
        if(u == t || !a) return a;
        int flow = 0, f;
        for(int& i = cur[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    int MaxFlow(int _s, int _t) {
        s = _s; t = _t;
        int flow = 0;
        while(BFS()) {
            rep(i, 1, n) cur[i] = head[i];
            flow += DFS(s, oo);
        }
        return flow;
    }
} sol;

int eid[maxm], low[maxm], in_f[maxn], out_f[maxn];

int main() {
    int n = read(), m = read(), s = n + 1, t = n + 2, sum = 0;
    sol.init();
    sol.setn(t);
    rep(i, 1, m) {
        int u = read(), v = read(), l = read(), r = read();
        if(l > r) return puts("NO"), 0;
        eid[i] = sol.m; low[i] = l;
        sol.AddEdge(u, v, r - l);
        in_f[v] += l; out_f[u] += l;
    }
    rep(i, 1, n)
        if(in_f[i] > out_f[i]) sol.AddEdge(s, i, in_f[i] - out_f[i]), sum += in_f[i] - out_f[i];
        else if(out_f[i] > in_f[i]) sol.AddEdge(i, t, out_f[i] - in_f[i]);
    
    if(sol.MaxFlow(s, t) < sum) return puts("NO"), 0;
    puts("YES");
    rep(i, 1, m) printf("%d\n", low[i] + sol.es[eid[i]^1].flow);
    
    return 0;
}

4、有源汇有上下界最大流。[LOJ#116]

从原图汇点向原图源点加一条容量无穷下界为 \(0\) 的边 \(e\),求出可行流,(若存在可行流)然后从原图中的源点到原图汇点跑一遍最大流就是答案。

有两点小问题:

1) 新建的源点、汇点是否会影响最后那一遍最大流?

A:不会的,因为如果存在解,那么新建的边就是满流的,即它们都指向源,或从汇指出,不肯能通过他们形成增广路。

2) 为什么直接跑最大流就是答案,不需要加上求完可行流后 \(e\) 上的流量吗?

A:不需要,因为第二遍最大流会把第一次在 \(e\) 上跑出的流量自动退回去——它会自动给你把这部分答案算上。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 212
#define maxm 20412
#define oo 2147483647

struct Edge {
    int from, to, flow;
    Edge() {}
    Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
};
struct Dinic {
    int n, m, s, t, head[maxn], nxt[maxm];
    Edge es[maxm];
    int vis[maxn], Q[maxn], hd, tl;
    int cur[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c) {
        es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS() {
        memset(vis, 0, sizeof(vis));
        vis[t] = 1;
        hd = tl = 0; Q[++tl] = t;
        while(hd < tl) {
            int u = Q[++hd];
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(!vis[e.from] && e.flow) {
                    vis[e.from] = vis[u] + 1;
                    Q[++tl] = e.from;
                }
            }
        }
        return vis[s] > 0;
    }
    
    int DFS(int u, int a) {
        if(u == t || !a) return a;
        int flow = 0, f;
        for(int& i = cur[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow)))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    int MaxFlow(int _s, int _t) {
        s = _s; t = _t;
        int flow = 0;
        while(BFS()) {
            rep(i, 1, n) cur[i] = head[i];
            flow += DFS(s, oo);
        }
        return flow;
    }
} sol;

int eid[maxm], low[maxm], in_f[maxn], out_f[maxn];

int main() {
    int n = read(), m = read(), S = read(), T = read(), s = n + 1, t = n + 2, sum = 0;
    sol.init();
    sol.setn(t);
    rep(i, 1, m) {
        int u = read(), v = read(), l = read(), r = read();
        if(l > r) return puts("please go home to sleep"), 0;
        eid[i] = sol.m; low[i] = l;
        sol.AddEdge(u, v, r - l);
        in_f[v] += l; out_f[u] += l;
    }
    sol.AddEdge(T, S, oo);
    rep(i, 1, n)
        if(in_f[i] > out_f[i]) sol.AddEdge(s, i, in_f[i] - out_f[i]), sum += in_f[i] - out_f[i];
        else if(out_f[i] > in_f[i]) sol.AddEdge(i, t, out_f[i] - in_f[i]);
    
    if(sol.MaxFlow(s, t) < sum) return puts("please go home to sleep"), 0;
    printf("%d\n", sol.MaxFlow(S, T));
    
    return 0;
}

5、有源汇有上下界最小流。[LOJ#117]

从原图汇点向汇点加一条容量无穷下界为 \(0\) 的边 \(e\),求出可行流,记此时边 \(e\) 上的流量为 \(flow_e\);然后删掉边 \(e\),从原图汇点向原图源点跑一遍最大流,这次最大流答案记为 \(f\),那么最终答案为 \(flow_e - f\)

可能产生的疑惑见上一题。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 50013
#define maxm 350022
#define oo 2147483647

struct Edge {
    int from, to, flow;
    Edge() {}
    Edge(int _1, int _2, int _3): from(_1), to(_2), flow(_3) {}
};
struct Dinic {
    int n, m, s, t, head[maxn], nxt[maxm];
    Edge es[maxm];
    int vis[maxn], Q[maxn], hd, tl;
    int cur[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c) {
        es[m] = Edge(a, b, c); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS(bool block) {
        memset(vis, 0, sizeof(vis));
        vis[t] = 1;
        hd = tl = 0; Q[++tl] = t;
        while(hd < tl) {
            int u = Q[++hd];
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(block && e.from == s && e.to == t) continue;
                if(!vis[e.from] && e.flow) {
                    vis[e.from] = vis[u] + 1;
                    Q[++tl] = e.from;
                }
            }
        }
        return vis[s] > 0;
    }
    
    int DFS(int u, int a, bool block) {
        if(u == t || !a) return a;
        int flow = 0, f;
        for(int& i = cur[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(block && u == s && e.to == t) continue;
            if(vis[e.to] == vis[u] - 1 && (f = DFS(e.to, min(a, e.flow), block))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    int MaxFlow(int _s, int _t, bool block) {
        s = _s; t = _t;
        int flow = 0;
        while(BFS(block)) {
            rep(i, 1, n) cur[i] = head[i];
            flow += DFS(s, oo, block);
        }
        return flow;
    }
} sol;

int eid[maxm], low[maxm], in_f[maxn], out_f[maxn];

int main() {
    int n = read(), m = read(), S = read(), T = read(), s = n + 1, t = n + 2, sum = 0;
    sol.init();
    sol.setn(t);
    rep(i, 1, m) {
        int u = read(), v = read(), l = read(), r = read();
        if(l > r) return puts("please go home to sleep"), 0;
        eid[i] = sol.m; low[i] = l;
        sol.AddEdge(u, v, r - l);
        in_f[v] += l; out_f[u] += l;
    }
    int cure = sol.m;
    sol.AddEdge(T, S, oo);
    rep(i, 1, n)
        if(in_f[i] > out_f[i]) sol.AddEdge(s, i, in_f[i] - out_f[i]), sum += in_f[i] - out_f[i];
        else if(out_f[i] > in_f[i]) sol.AddEdge(i, t, out_f[i] - in_f[i]);
    
    int flow = sol.MaxFlow(s, t, 0);
    int tmp = sol.es[cure^1].flow;
    if(flow < sum) return puts("please go home to sleep"), 0;
    printf("%d\n", tmp - sol.MaxFlow(T, S, 1));
    
    return 0;
}

6、最小费用可行流(带负环、下界)。[ZZOJ#30]

先强行所有边权为负的边流满上界,边权为正的边流成下界,然后用可行流的方法调整。注意调整时跑的是最小费用最大流,而不是最小费用流。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
#define rep(i, s, t) for(int i = (s); i <= (t); i++)
#define dwn(i, s, t) for(int i = (s); i >= (t); i--)

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); }
    return x * f;
}

#define maxn 310
#define maxm 6010
#define oo 2147483647
#define LL long long

struct Edge {
    int from, to, flow, cost;
    Edge() {}
    Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
};
struct ZKW {
    int n, m, s, t, cost, head[maxn], nxt[maxm];
    LL ans;
    Edge es[maxm];
    int d[maxn];
    bool inq[maxn];
    deque <int> Q;
    bool vis[maxn];
    
    void init() {
        m = 0; memset(head, -1, sizeof(head));
        return ;
    }
    void setn(int _) {
        n = _;
        return ;
    }
    
    void AddEdge(int a, int b, int c, int d) {
        es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
        es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
        return ;
    }
    
    bool BFS() {
        rep(i, 1, n) d[i] = oo;
        d[t] = 0;
        Q.push_back(t); inq[t] = 1;
        while(!Q.empty()) {
            int u = Q.front(); Q.pop_front(); inq[u] = 0;
            for(int i = head[u]; i != -1; i = nxt[i]) {
                Edge& e = es[i^1];
                if(d[e.from] > d[u] + e.cost && e.flow) {
                    d[e.from] = d[u] + e.cost;
                    if(!inq[e.from]) {
                        inq[e.from] = 1;
                        if(Q.empty() || d[e.from] <= d[Q.front()]) Q.push_front(e.from);
                        else Q.push_back(e.from);
                    }
                }
            }
        }
        if(d[s] == oo) return 0;
        cost = d[s];
        return 1;
    }
    
    int DFS(int u, int a) {
        if(u == t || !a) return ans += (LL)cost * a, a;
        if(vis[u]) return 0;
        vis[u] = 1;
        int flow = 0, f;
        for(int i = head[u]; i != -1; i = nxt[i]) {
            Edge& e = es[i];
            if(d[e.to] == d[u] - e.cost && (f = DFS(e.to, min(a, e.flow)))) {
                flow += f; a -= f;
                e.flow -= f; es[i^1].flow += f;
                if(!a) return flow;
            }
        }
        return flow;
    }
    
    int MaxFlow(int _s, int _t) {
        s = _s; t = _t;
        int flow = 0, f;
        while(BFS())
            do {
                memset(vis, 0, sizeof(vis));
                f = DFS(s, oo);
                flow += f;
            } while(f);
        return flow;
    }
} sol;

int in_f[maxn], out_f[maxn], eid[maxm], low[maxm];
bool rev[maxm];

int main() {
    int n = read(), m = read(), s = n + 1, t = s + 1;
    LL ans = 0;
    sol.init(); sol.setn(t);
    rep(i, 1, m) {
        int a = read(), b = read(), lower = read(), upper = read(), cost = read();
        if(cost >= 0) {
            ans += (LL)lower * cost;
            in_f[b] += lower; out_f[a] += lower;
            low[i] = lower; eid[i] = sol.m;
            sol.AddEdge(a, b, upper - lower, cost);
        }
        if(cost < 0) {
            ans += (LL)upper * cost;
            in_f[b] += upper; out_f[a] += upper;
            low[i] = upper; eid[i] = sol.m; rev[i] = 1;
            sol.AddEdge(b, a, upper - lower, -cost);
        }
    }
    int need_f = 0;
    rep(i, 1, n) {
        if(in_f[i] > out_f[i]) sol.AddEdge(s, i, in_f[i] - out_f[i], 0), need_f += in_f[i] - out_f[i];
        if(out_f[i] > in_f[i]) sol.AddEdge(i, t, out_f[i] - in_f[i], 0);
    }
    if(sol.MaxFlow(s, t) < need_f) return puts("QAQ"), 0;
    printf("%lld\n", ans + sol.ans);
//  rep(i, 1, m) printf("%d\n", low[i] + (sol.es[eid[i]^1].flow * (rev[i] ? -1 : 1)));
    
    return 0;
}

以上是关于网络流模板大全的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段3——url大全

VSCode自定义代码片段3——url大全

VSCode自定义代码片段——cli的终端命令大全

VSCode自定义代码片段4——cli的终端命令大全

模板网络最大流

网络流模板