ZOJ 2314 Reactor Cooling

无汇源上下界可行流的模板题。
说是模板题,其实想让它除了二分以外加点变化也是有点困难的。

关于上下界网络流的问题,以前偷懒没学,本来打算这几天补上,加上今天薛昊这个催化剂又来问我,于是就今天开始补了。

在这里我非常非常非常非常非常推荐这篇博文
总结的非常详细,写的有十分通俗易懂,全文十分连贯,评论也有人说看完给人一种荡气回肠的感觉。
当我看完无汇源上下界可行流的时候,我马上敲了一蛤这道题,就一 A 了。妙啊!

下面简单说一下无汇源上下界可行流的解法,不详细说明,具体请看上面的链接。
无汇源上下界可行流可用建图+最大流解决,建图方式如下:

  • 对每个给定的边建边,容量为 up – down
  • 记录每个点的 down 流量差,这里设 入流量为正,出流量为负。如果总的流量差大于0,建边 src -> 该点,容量为流量差。否则,建边 该点 -> des 容量为流量差的负值。

没了,再跑一遍最大流,如果能满流就说明有可行流,否则无解。

题意:
无汇源上下界可行流裸题。

思路:
见上。

AC Code

#include <bits/stdc++.h>

using namespace std;

using namespace std;
const int maxn = 204;
const int maxm = 4e4 + 5;
const int inf = 0x3f3f3f3f;

int n, m, src, des, idx;
int cur[maxn], level[maxn], head[maxn];
int cap[maxm];

struct node {
    int to, next;
    int cap;
    node() {}
    node(int _to, int _next, int _cap) { to = _to, next = _next, cap = _cap; }
} edges[maxm];

queue<int> que;

int getNode(int a, int b) { return a * m + b; }

void addEdge(int u, int v, int c)
{
    edges[idx] = node(v, head[u], c);
    head[u] = idx++;
    edges[idx] = node(u, head[v], 0);
    head[v] = idx++;
}

bool bfs()
{
    memset(level, -1, sizeof level);
    que.push(src);
    level[src] = 0;
    int u;
    while (!que.empty()) {
        u = que.front();
        que.pop();
        for (int id = head[u]; ~id; id = edges[id].next) {
            int v = edges[id].to;
            if (edges[id].cap > 0 && level[v] == -1) {
                level[v] = level[u] + 1;
                que.push(v);
            }
        }
    }
    return level[des] != -1;
}

int dfs(int u, int low)
{
    int cflow;
    if (u == des)
        return low;
    for (int& id = cur[u]; ~id; id = edges[id].next) {
        int v = edges[id].to;
        if (edges[id].cap > 0 && level[v] == level[u] + 1
            && (cflow = dfs(v, min(low, edges[id].cap)))) {
            edges[id].cap -= cflow;
            edges[id ^ 1].cap += cflow;
            return cflow;
        }
    }
    return 0;
}

int dinic()
{
    int ans = 0, cflow;
    while (bfs()) {
        for (int i = 0; i <= des; i++)
            cur[i] = head[i];
        while ((cflow = dfs(src, inf)))
            ans += cflow;
    }
    return ans;
}

void init(int st, int en)
{
    memset(head, -1, sizeof head);
    idx = 0;
    src = st, des = en;
}

int deg[maxn], down[maxm];

int main()
{
    int T, u, v, up;
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &m);
        init(0, n + 1);
        memset(deg, 0, sizeof deg);
        for (int i = 0; i < m; i++) {
            scanf("%d %d %d %d", &u, &v, &down[i], &up);
            addEdge(u, v, up - down[i]);
            deg[u] -= down[i], deg[v] += down[i];
        }
        int sum = 0;
        for (int i = 1; i <= n; i++)
            if (deg[i] > 0) {
                addEdge(src, i, deg[i]);
                sum += deg[i];
            } else
                addEdge(i, des, -deg[i]);
        if (dinic() < sum) {
            puts("NO");
        } else {
            puts("YES");
            for (int i = 0; i < m; i++)
                printf("%d\n", edges[i << 1 | 1].cap + down[i]);
        }
    }
    return 0;
}