首页 > 技术文章 > 有源汇有上下界最大/最小流

Kong-Ruo 原文

建图还是要想一想的...写一下吧

首先根据有源汇可行流建图,正向附加边满流证明有可行流

然后在这个残量网络上删掉 $(t,s,oo)$ 这条边,跑 $s->t$ 最大流就是最大流,$t->s$ 最大流就是最小流

#include <bits/stdc++.h>
#define int long long
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1;
    char ch;
    for (ch = getchar(); !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = -f;
    for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 500010;
struct Dinic {
#define oo 21474832333333LL
    int n, m, s, t;
    int cur[maxn], head[maxn], nx[maxn];
    struct Edge {
        int from, to, caps;
        Edge() {}
        Edge(int _1, int _2, int _3) : from(_1), to(_2), caps(_3) {}
    } es[maxn];
    void add(int u, int v, int w) {
        es[m] = Edge(u, v, w);
        nx[m] = head[u];
        head[u] = m++;
        es[m] = Edge(v, u, 0);
        nx[m] = head[v];
        head[v] = m++;
    }
    Dinic() {
        m = 0;
        memset(head, -1, sizeof(head));
    }
    queue<int> q;
    int dis[maxn];
    int BFS() {
        for (int i = 0; i <= n; i++) dis[i] = 0;
        dis[t] = 1;
        q.push(t);
        while (!q.empty()) {
            int now = q.front();
            q.pop();
            for (int i = head[now]; i != -1; i = nx[i]) {
                Edge &e = es[i ^ 1];
                if (!dis[e.from] && e.caps) {
                    dis[e.from] = dis[now] + 1;
                    q.push(e.from);
                }
            }
        }
        return (dis[s] > 1);
    }
    int DFS(int u, int a) {
        if (u == t || !a)
            return a;
        int flow = 0, f;
        for (int &i = cur[u]; i != -1; i = nx[i]) {
            Edge &e = es[i];
            if (dis[e.to] == dis[u] - 1 && (f = DFS(e.to, min(e.caps, a)))) {
                flow += f;
                a -= f;
                e.caps -= f;
                es[i ^ 1].caps += f;
                if (a == 0)
                    return flow;
            }
        }
        return flow;
    }
    int MaxFlow(int _s, int _t) {
        s = _s, t = _t;
        int flow = 0, f;
        while (BFS()) {
            for (int i = 0; i <= n; i++) cur[i] = head[i];
            while (f = DFS(s, oo)) flow += f;
        }
        return flow;
    }
} sol;
int ind[maxn];
signed main() {
    int n = read(), m = read(), s = read(), t = read(), SS = n + 1, TT = n + 2;
    for (int i = 1; i <= m; i++) {
        int u = read(), v = read(), b = read(), a = read();
        sol.add(u, v, a - b); ind[v] += b; ind[u] -= b;
    } sol.n = n + 5;
    int totflow = 0;
    rep(u, 1, n) {
        if(ind[u] > 0) sol.add(SS, u, ind[u]), totflow += ind[u];
        if(ind[u] < 0) sol.add(u, TT, -ind[u]);
    }
    sol.add(t, s, oo);
    int rflow = sol.MaxFlow(SS, TT);
    if(totflow > rflow) {
        cout << "please go home to sleep" << endl;
        return 0;
    } sol.es[m - 1].caps = sol.es[m - 2].caps = 0;
    cout << oo - sol.MaxFlow(t, s) << endl;
}
最小流
#include <bits/stdc++.h>
#define int long long
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1;
    char ch;
    for (ch = getchar(); !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = -f;
    for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 200010;
struct Dinic {
#define oo 21474832333333LL
    int n, m, s, t;
    int cur[maxn], head[maxn], nx[maxn];
    struct Edge {
        int from, to, caps;
        Edge() {}
        Edge(int _1, int _2, int _3) : from(_1), to(_2), caps(_3) {}
    } es[maxn];
    void add(int u, int v, int w) {
        es[m] = Edge(u, v, w);
        nx[m] = head[u];
        head[u] = m++;
        es[m] = Edge(v, u, 0);
        nx[m] = head[v];
        head[v] = m++;
    }
    Dinic() {
        m = 0;
        memset(head, -1, sizeof(head));
    }
    queue<int> q;
    int dis[maxn];
    int BFS() {
        for (int i = 0; i <= n; i++) dis[i] = 0;
        dis[t] = 1;
        q.push(t);
        while (!q.empty()) {
            int now = q.front();
            q.pop();
            for (int i = head[now]; i != -1; i = nx[i]) {
                Edge &e = es[i ^ 1];
                if (!dis[e.from] && e.caps) {
                    dis[e.from] = dis[now] + 1;
                    q.push(e.from);
                }
            }
        }
        return (dis[s] > 1);
    }
    int DFS(int u, int a) {
        if (u == t || !a)
            return a;
        int flow = 0, f;
        for (int &i = cur[u]; i != -1; i = nx[i]) {
            Edge &e = es[i];
            if (dis[e.to] == dis[u] - 1 && (f = DFS(e.to, min(e.caps, a)))) {
                flow += f;
                a -= f;
                e.caps -= f;
                es[i ^ 1].caps += f;
                if (a == 0)
                    return flow;
            }
        }
        return flow;
    }
    int MaxFlow(int _s, int _t) {
        s = _s, t = _t;
        int flow = 0, f;
        while (BFS()) {
            for (int i = 0; i <= n; i++) cur[i] = head[i];
            while (f = DFS(s, oo)) flow += f;
        }
        return flow;
    }
} sol;
int ind[maxn];
signed main() {
    int n = read(), m = read(), s = read(), t = read(), SS = n + 1, TT = n + 2;
    for (int i = 1; i <= m; i++) {
        int u = read(), v = read(), b = read(), a = read();
        sol.add(u, v, a - b);
        ind[v] += b;
        ind[u] -= b;
    }
    sol.n = n + 5;
    int totflow = 0;
    rep(u, 1, n) {
        if (ind[u] > 0)
            sol.add(SS, u, ind[u]), totflow += ind[u];
        if (ind[u] < 0)
            sol.add(u, TT, -ind[u]);
    }
    sol.add(t, s, oo);
    int rflow = sol.MaxFlow(SS, TT);
    if (totflow > rflow) {
        cout << "please go home to sleep" << endl;
        return 0;
    }
    sol.es[m - 1].caps = sol.es[m - 2].caps = 0;
    cout << sol.MaxFlow(s, t) << endl;
}
最大流

 记住,删边的时候不是 $m$,是 $sol.m$

推荐阅读