zoukankan      html  css  js  c++  java
  • 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
    ",B[i] + edge[i * 2 + 1].w); //输出的是下限 + 反向边
            }else{
                puts("NO");
            }
            puts("");
        }
    }
  • 相关阅读:
    归并排序
    汉诺塔系列问题: 汉诺塔II、汉诺塔III、汉诺塔IV、汉诺塔V、汉诺塔VI、汉诺塔VII
    Uncle Tom's Inherited Land
    汉诺塔III
    汉诺塔X
    Frosh Week
    hdu 1007最近点对问题
    POJ1579:Function Run Fun
    Hdu1163 Eddy's digitai Roots(九余数定理)
    放苹果问题
  • 原文地址:https://www.cnblogs.com/Jadon97/p/9638600.html
Copyright © 2011-2022 走看看