USACO 4.2 Drainage Ditches

题目大意:

    下了大雨要排水,从一个点排到另一个点,中间有很多的小河流,每个河流有自己的流量,小流又有小流。。。求出最大排出多少水(n<200)

解题思路:

    网络流的模板题,一个点到一个点的最大流量,网络流我打的是dinic,听说一般只要会这个就好了..
打法就是用搜索每次找出一条可以到达终点的路径,全部流量去减了最小路径的流量。

程序:

type
        arr=record
                k,data,next,ref:longint;
        end;
const
        maxn=200;
var
        i,j,n,p,q,x,m,o,p1,p2,p3,dalta,maxflow:longint;
        a:array [0..maxn*10] of arr;
        aw,last,d,z,path:array [0..maxn*10] of longint;
        flag:array [0..maxn*10] of boolean;

function min(x,y:longint):longint;
begin
        if x<y then exit(x)
               else exit(y);
end;

procedure add(p,q,x:longint);
begin
        inc(o);
        a[o].k:=q;
        a[o].data:=x;
        a[o].next:=last[p];
        a[o].ref:=o+1;
        last[p]:=o;
        inc(o);
        a[o].k:=p;
        a[o].data:=0;
        a[o].next:=last[q];
        a[o].ref:=o-1;
        last[q]:=o;
end;

procedure relax(p,q:longint);
begin
        if aw[q]>aw[p]+1 then
        begin
                aw[q]:=aw[p]+1;
                if not flag[q] then
                begin
                        flag[q]:=true;
                        inc(p3);
                        inc(p2);
                        if p2>maxn*10 then p2:=1;
                        d[p2]:=q;
                end;
        end;
end;



function spfa:boolean;
var
        i,j:longint;
begin
       fillchar(flag,sizeof(flag),false);
       fillchar(aw,sizeof(aw),10);
       d[1]:=1;
       aw[1]:=0;
       flag[1]:=true;
       p1:=1; p2:=1; p3:=1;
       repeat
        i:=last[d[p1]];
        while i<>0 do
        begin
                if a[i].data>0 then relax(d[p1],a[i].k);
                i:=a[i].next;
        end;
        flag[d[p1]]:=false;
        dec(p3);
        inc(p1);
        if p1>maxn*10 then p1:=1;
       until p3=0;
       if aw[m]<99999 then exit(true) else exit(false);
end;

procedure work;
var
        i,j,k:longint;
begin
        z[0]:=1;
        z[1]:=1;
        repeat
                k:=z[z[0]];
                if k<>m then
                begin
                        j:=last[k];
                        while (j<>0) and ((a[j].data=0) or (aw[a[j].k]<>aw[k]+1)) do j:=a[j].next;
                        if j>0 then
                        begin
                                path[z[0]]:=j;
                                inc(z[0]);
                                z[z[0]]:=a[j].k;
                        end else
                        begin
                                aw[k]:=999999;
                                dec(z[0]);
                        end;
                end else
                begin
                        dalta:=999999999;
                        for i:=1 to z[0]-1 do
                         dalta:=min(dalta,a[path[i]].data);
                        inc(maxflow,dalta);
                        for i:=z[0]-1 downto 1 do
                        begin
                                dec(a[path[i]].data,dalta);
                                inc(a[a[path[i]].ref].data,dalta);
                                if a[path[i]].data=0 then k:=i;
                        end;
                        z[0]:=k;
                end;
        until z[0]=0;
end;

begin
        readln(n,m);
        for i:=1 to n do
        begin
                readln(p,q,x);
                add(p,q,x);
        end;
        maxflow:=0;

        while spfa do work;
        writeln(maxflow);
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值