zoukankan      html  css  js  c++  java
  • [ZOJ2341]Reactor Cooling解题报告|带上下界的网络流|无源汇的可行流

    Reactor Cooling

    The terrorist group leaded by a well known international terrorist Ben Bladen is buliding a nuclear reactor to produce plutonium for the nuclear bomb they are planning to create. Being the wicked computer genius of this group, you are responsible for developing the cooling system for the reactor.

    The cooling system of the reactor consists of the number of pipes that special cooling liquid flows by. Pipes are connected at special points, called nodes, each pipe has the starting node and the end point. The liquid must flow by the pipe from its start point to its end point and not in the opposite direction.

    Let the nodes be numbered from 1 to N. The cooling system must be designed so that the liquid is circulating by the pipes and the amount of the liquid coming to each node (in the unit of time) is equal to the amount of liquid leaving the node. That is, if we designate the amount of liquid going by the pipe from i-th node to j-th as fij, (put fij= 0 if there is no pipe from node i to node j), for each i the following condition must hold:

    fi,1+fi,2+...+fi,N = f1,i+f2,i+...+fN,i

    Each pipe has some finite capacity, therefore for each i and j connected by the pipe must be fij <= cij where cij is the capacity of the pipe. To provide sufficient cooling, the amount of the liquid flowing by the pipe going from i-th to j-th nodes must be at least lij, thus it must be fij >= lij.

    Given cij and lij for all pipes, find the amount fij, satisfying the conditions specified above.

    This problem contains multiple test cases!

    The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

    The output format consists of N output blocks. There is a blank line between output blocks.

    Input

    The first line of the input file contains the number N (1 <= N <= 200) - the number of nodes and and M - the number of pipes. The following M lines contain four integer number each - i, j, lij and cij each. There is at most one pipe connecting any two nodes and 0 <= lij <= cij <= 10^5 for all pipes. No pipe connects a node to itself. If there is a pipe from i-th node to j-th, there is no pipe from j-th node to i-th.

    Output

    On the first line of the output file print YES if there is the way to carry out reactor cooling and NO if there is none. In the first case M integers must follow, k-th number being the amount of liquid flowing by the k-th pipe. Pipes are numbered as they are given in the input file.

      第一次在浙大的OJ上做题w

      题意大概就是给定一张管道网络以及每一根管道流量的上界和下界

      判断是否存在可行流,以及如果存在的话输出一组可行流

      感谢NewFarking的文章 (戳这里

      做法还是理解了一会儿的呢..

      对于一根管道(u,v),设其流量限制为[l,r]

      为了简便地解决这个问题我们有一个初步的想法

      就是先强制流掉下限流量,然后剩下的给出流量限制之后再随意流

      

      实际上代码也基本是这样实现的

      先从u到v连一条容量为r-l的边,也就是自由流

      看起来我们将这根管道的下限流确实是流掉了呢

      但是整张网络并没有

      比如这张图

      w到u必须流掉的10单位流量,但从u出发只强制流掉了5单位的流量

      还有5单位的流量必须流出去

      用什么来强制流出去呢?

      答案是从s到u建一条容量为5的边

      因为我们最终判断是否存在可行流的条件是s连出的边是否全部满流

      那么一旦存在可行解,这5个单位的流量全流出去了,能达到我们的目的

      这道题让我们输出一组可行解,我是在Dfs的过程中处理的


      

      UPD.顺便写一写其他几种的建图方法:

      有源汇的可行流:转换成无源汇的可行流来做,即从t→s连一条容量为正无穷

      无下限的边,整个图就转化成了循环图

      有源汇的最大流/有源汇的最小流:拆边的方法太奇怪不好理解

      二分t→s的下限即可

    program zoj2314;
    const maxn = 210;maxm = 80010;
    var fa,next,ter,w,rec,flow:array[-1..maxm]of longint;
        link,dis,opt,inp:array[-1..maxn]of longint;
        vis:array[-1..maxn]of boolean;
        n,m,e,tt,test,i,s,t,x,y,l,r:longint;
    
    function min(a,b:longint):longint;
    begin
            if a<b then exit(a) else exit(b);
    end;
    
    function spfa:boolean;
    var head,tail,x,j:longint;
    begin
        fillchar(vis,sizeof(vis),true);
        fillchar(dis,sizeof(dis),63);
        head:=0;tail:=1;opt[1]:=s;vis[s]:=false;dis[s]:=0;
        while head<>tail do
        begin
            head:=(head+1) mod maxn;
            x:=opt[head];j:=link[x];
            while j<>0 do
            begin
                if (dis[x]+1<dis[ter[j]])and(w[j]>0) then
                begin
                    dis[ter[j]]:=dis[x]+1;
                    if vis[ter[j]] then
                    begin
                        vis[ter[j]]:=false;
                        tail:=(tail+1) mod maxn;
                        opt[tail]:=ter[j];
                    end;
                end;
                j:=next[j];
            end;
            vis[x]:=true;
        end;
        if dis[t]<>dis[t+1] then exit(true) else exit(false);
    end;
    
    function dfs(p,sum:longint):longint;
    var tem,j,x:longint;
    begin
        tem:=0;
        if p=t then exit(sum);
        j:=link[p];
        while j<>0 do
         begin
            if (dis[ter[j]]=dis[p]+1)and(w[j]>0) then
            begin
                x:=dfs(ter[j],min(sum-tem,w[j]));
                inc(tem,x);dec(w[j],x);inc(w[rec[j]],x);
                           // writeln(p,' ',ter[j],' ',fa[j],' ',x);
                if rec[j]=j+1 then inc(flow[fa[j]],x) else dec(flow[fa[rec[j]]],x);
                if tem=sum then exit(sum);
            end;
            j:=next[j];
        end;
        exit(tem);
    end;
    
    procedure add(x,y,z,fat:longint);
    begin
           // writeln(x,' ',y,' ',z);
        inc(e);ter[e]:=y;next[e]:=link[x];link[x]:=e;w[e]:=z;fa[e]:=fat;rec[e]:=e+1;
        inc(e);ter[e]:=x;next[e]:=link[y];link[y]:=e;w[e]:=0;fa[e]:=fat;rec[e]:=e-1;
    end;
    
    function Jud:boolean;
    var j:longint;
    begin
        j:=link[s];
        while j<>0 do
        begin
            if w[j]>0 then exit(false);
            j:=next[j];
        end;
        exit(true);
    end;
    
    procedure Solve;
    var i,sum:longint;
    begin
            sum:=0;
        while spfa do inc(sum,dfs(s,1000000007));
        if not Jud then writeln('NO') else
        begin
            writeln('YES');
            for i:=1 to m do writeln(flow[i]);
        end;
        writeln;
    end;
    
    begin
        //assign(input,'zoj2314.in');reset(input);
        readln(test);
        for tt:=1 to test do
        begin
            readln;
            readln(n,m);
            fillchar(inp,sizeof(inp),0);
            fillchar(link,sizeof(link),0);
            fillchar(next,sizeof(next),0);
            e:=0;s:=0;t:=n+1;
            for i:=1 to m do
            begin
                readln(x,y,l,r);
                            flow[i]:=l;
                dec(inp[x],l);inc(inp[y],l);
                add(x,y,r-l,i);
            end;
            for i:=1 to n do if inp[i]>0 then add(s,i,inp[i],0) else
                if inp[i]<0 then add(i,t,-inp[i],0);
            Solve;
        end;
    end.
  • 相关阅读:
    新年献礼 技术胖262集前端免费视频 让您走的更容易些
    Eruda 一个被人遗忘的调试神器
    你(可能)不知道的web api
    含有阶乘的幂级数和
    sin x 特解的假设
    将y=arctanx展开为x的幂级数
    判断数项级数是否收敛
    ubuntu中用安装字体的方法解决文档中的音标乱码
    英语单词
    用递归实现汉诺塔
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4465832.html
Copyright © 2011-2022 走看看