ZOJ 2314 (sgu 194) Reactor Cooling (无源汇有上下界最大流)

题意:

给定n个点和m条边, 每条边有流量上下限[b,c], 求是否存在一种流动方法使得每条边流量在范围内, 而且每个点的流入 = 流出

分析:

无源汇有上下界最大流模板, 记录每个点流的 in 和 out , 然后如果一个点 i 的in > out,  从源点i连一条边到in, out > in 就从i 连一条边到 v.

#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int maxN = 1e5 + 7;
const int maxM = 2e6 + 7;
const int INF = 1e9 + 7;
int n, m, S, T, ecnt;
int in[maxN], out[maxN], B[maxN];
int head[maxN];
struct {
    int to, nxt, w;
} edge[maxM];
void init() {
    memset(in, 0, sizeof(in));
    memset(out, 0, sizeof(out));
    memset(B, 0, sizeof(B));
    ecnt = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v, int w) {
    edge[ecnt].nxt = head[u];
    edge[ecnt].to = v;
    edge[ecnt].w = w;
    head[u] = ecnt++;
}
int depth[maxN];

bool bfs() {
    memset(depth, -1, sizeof(depth));
    queue<int> q;
    depth[S] = 0;
    q.push(S);
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        for(int i = head[u]; i != -1; i = edge[i].nxt) {
            int v = edge[i].to, w = edge[i].w;
            if(w > 0 && depth[v] == -1) { //若该残量不为0,且V[i]还未分配深度,则给其分配深度并放入队列
                depth[v] = depth[u] + 1;
                q.push(v);
            }
        }
    }
    if(depth[T] == -1)
        return false;
    return true;//当汇点的深度不存在时,说明不存在分层图,同时也说明不存在增广路
}
int dfs(int u, int flow) { //u为当前节点 , flow为当前流量
    if(u == T) //已经到达汇点, 直接返回
        return flow;

    for(int i = head[u]; i != -1; i = edge[i].nxt) {
        int v = edge[i].to, w = edge[i].w;
        if((depth[v] == depth[u] + 1) && (w != 0)) { //注意这里要满足分层图和残量不为0两个条件
            int di = dfs(v, min(flow, w));
            if(di > 0) {
                edge[i].w -= di;
                edge[i ^ 1].w += di; //边是相反的两条, 奇数-1 偶数+1
                return di;
            }
        }
    }
    return 0; //没有増广路
}
int Dinic() {
    int ans = 0, d = 0;
    while(bfs()) {
        while(d = dfs(S, INF))
            ans += d;
    }
    return ans;
}
int main() {
//    freopen("1.txt","r", stdin);
    ios::sync_with_stdio(false);
    int Test;
    cin >> Test;
    while(Test--) {
        cin >> n >> m;
        init();
        S = n + 1, T = n + 2;
        for(int i = 0; i < m; i++) {
            int u, v, b, c;
            cin >> u >> v >> b >> c;
            addEdge(u,v,c - b);
            addEdge(v,u, 0);
            B[i] = b;
            out[u] += b;//记录入流
            in[v] += b;// 记录出流
        }

        int sum = 0;

        for(int i = 1; i <= n; i++) { //加边
            int tmp = in[i] - out[i];
            if(tmp > 0) {
                addEdge(S, i, tmp);
                addEdge(i, S, 0);
                sum += tmp;
            } else {
                addEdge(i, T, -tmp);
                addEdge(T, i, 0);
            }
        }

        int ans = Dinic();

        if(ans == sum) {
            puts("YES");
            for(int i = 0; i < m; i ++)
                printf("%d\n",B[i] + edge[i * 2 + 1].w); //输出的是下限 + 反向边
        }else{
            puts("NO");
        }
        puts("");
    }
}

猜你喜欢

转载自www.cnblogs.com/Jadon97/p/9638600.html