ZOJ2314 Reactor Cooling

一.题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314

二,题目大意:给一个无汇源点,流量有上下界限的图,求出是否有可行流,如果有,输出每条管子上的最大流。

三.思路:首先判断有无可行流,由于流量有上下界,于是,自然而然想到了每条弧用上界减去下界,但是这样违反了流量守恒(流入一个节点的流等于流出的)。

比如说:(u,v)上下界为(1,3), (v, q)上下界为(3,4)一条边减去2,另一条边减去了1,减去的流量不相等,相当于1的流量积累在v。于是我们可以想到建立源点、汇点来导流。

具体建图如下:

1.记录每个点的D = (每条进入它的弧的下界) 减去 (由它出发的弧的下界)。如果大于0,得到的就是积累在本节点的流量,于是建立一个汇点,把流导给它。容量为D。如果小于0,得到的就是本节点所需要进入的流量,建立一个源点s,跟它相连,容量为-D。

2.当然原来容量网络的每条弧保持一样,容量变为上界 减去 下界。

        对于构造出来的图我们叫它伴随网络,(当然它的每条弧下界都为0)只有伴随网络的最大流使得从源点S出发,每条弧都满了(此时连到T的弧也一定会满),原来网络才有可行流。而本题还要求原容量网络中每条弧的可行流的流量,其实它只等于伴随网络中所对应的弧的流量加上每条弧流量的下界。而对于邻接表建图的话,伴随网络中所对应的弧的流量,就是第2*i条边的反向弧最后的流量。也就是2*i^1。

四.代码:

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int INF = 0x3f3f3f3f,
          MAX_N = 209;

class Dinic
{
public:
    struct Edge
    {
        int v, w, next;
    };

    int cnt, head[MAX_N], dist[MAX_N], s, t;
    Edge edges[MAX_N*MAX_N];

    void init(int is, int it)
    {
        cnt = 0;
        s = is, t = it;
        memset(head, -1, sizeof(head));
    }

    void addEdge(int u, int v, int weight)
    {
        edges[cnt] = (Edge){v, weight, head[u]};
        head[u] = cnt++;
        edges[cnt] = (Edge){u, 0, head[v]};
        head[v] = cnt++;
    }

    bool BFS()
    {
        int i, cur;
        queue  que;
        que.push(s);
        memset(dist, -1, sizeof(dist));
        dist[s] = 0;
        while(!que.empty()){
            cur = que.front();
            que.pop();
            for(i = head[cur]; i != -1; i = edges[i].next)
                if(-1 == dist[edges[i].v] && edges[i].w){
                    dist[edges[i].v] = dist[cur] + 1;
                    que.push(edges[i].v);
                }
        }

        return dist[t] != -1;
    }

    int DFS(int start, int curFlow)
    {
        if(start == t)
            return curFlow;
        int i, minFlow = 0, v, temp;
        for(i = head[start]; i != -1; i = edges[i].next){
            v = edges[i].v;
            if(dist[start] == dist[v] - 1 && edges[i].w > 0){
                temp = DFS(v, min(edges[i].w, curFlow));
                edges[i].w -= temp;
                edges[i^1].w += temp;
                curFlow -= temp;
                minFlow += temp;
                if(0 == curFlow)
                    break;
            }
        }
        if(0 == minFlow)
            dist[start] = -2;
        return minFlow;
    }

    int maxFlow()
    {
        int res = 0;
        while(BFS()){
            res += DFS(s, INF);
        }
        return res;
    }
}G;

int nodeNum, edgeNum,
    cnt[MAX_N];
int main()
{
    //freopen("in.txt", "r", stdin);

    int sum, i, j, test, u, v, down[MAX_N*MAX_N], up, s, t;
    scanf("%d", &test);
    while(test--){
        scanf("%d%d", &nodeNum, &edgeNum);

        s = nodeNum + 1, t = nodeNum + 2;
        G.init(s, t);
        memset(cnt, 0, sizeof(cnt));

        for(i = 0; i < edgeNum; i++){
            scanf("%d%d%d%d", &u, &v, &down[i], &up);
            cnt[u] += down[i], cnt[v] -= down[i];
            G.addEdge(u, v, up - down[i]);
        }

        sum = 0;
        for(i = 1; i <= nodeNum; i++){
            if(cnt[i] > 0){
                G.addEdge(i, t, cnt[i]);
                sum += cnt[i];
            }
            else if(cnt[i] < 0)
                G.addEdge(s, i, -cnt[i]);
        }

        if(sum == G.maxFlow()){
            printf("YES\n");
            for(i = 0; i < edgeNum; i++)
                printf("%d\n", down[i] + G.edges[(2*i)^1].w);
            printf("\n");
        }
        else
            printf("NO\n\n");
    }

    return 0;
}



你可能感兴趣的:(网络流)