网络流Sap+Gap(【USACO题库】4.2.1 Drainage Ditches草地排水 )

来源:互联网 发布:mac玩魔兽世界非常热 编辑:程序博客网 时间:2024/04/28 08:11

网络流-Dinic在此

这里写图片描述

网络流的定义 & 概念 & 残余网络

没错这就是上面的链接
不多讲

Sap

其实Sap的核心思想和Dinic相同,都是通过编号来减少搜索次数
只不过,Sap效率(+Gap),代码复杂度都较小。

定义d[i]表示点i到汇点最少经过的弧数量。称作距离标号。
则弧(i,j)为允许弧的情况就是
d[i]=d[j]+1
每次走只走允许弧,这样效率会快很多。
这里写图片描述
经过处理距离标号后,从2就不会走到3,这样效率会快很多。

处理距离标号

可以通过反向BFS,从汇点往源点走,以此计算出距离标号。
不过这样做,需要把路径转向,比较麻烦。

实际上,可以一开始把所有距离标号都设为0,在寻找的过程中可以通过更新来更改,不会影响到正确性。

更新标号

每次查找完路径后,如果没有找到流,就把路径上的所有点更改距离标号。
d[i]=min(d[j])+1 (i,j间存在有流量的路径)

★Gap优化★(重点)

可以得知,距离标号的更改一定是单调递增的。
每一次重标号后,有可能标号间会出现断层(某一种标号不存在)
所以这个时候一定就没有路径到达汇点。

代码

var        s:array[1..200,1..200] of longint;        f:array[1..200] of longint;        gap:array[0..200] of longint;        n,m,i,j,k,l,x,y,z,ans,sum:longint;        find:boolean;function min(x,y:longint):longint;begin        if x<y then min:=x        else        min:=y;end;procedure dfs(t:longint);var        i,j,k,mn:longint;begin        k:=sum;        if t=m then//找到流        begin                find:=true;                ans:=ans+sum;                exit;        end;        mn:=m-1;//如果没找到路径那么该点就不可行        for i:=1 to m do        if s[t,i]>0 then//存在流量        begin                if f[t]=f[i]+1 then//允许弧                begin                        if s[t,i]<sum then//计算流量                        sum:=s[t,i];                        dfs(i);                        if find then//找到即退出                        break;                end;                sum:=k;//计算流量                mn:=min(mn,f[i]);//重标号        end;        if find=false then        begin                dec(gap[f[t]]);//Gap                if gap[f[t]]=0 then//Gap                begin                        writeln(ans);                        halt;                end;                f[t]:=mn+1;//重标号                inc(gap[f[t]]);//Gap        end        else        begin//反向弧                dec(s[t,i],sum);                inc(s[i,t],sum);        end;end;begin        readln(n,m);        for i:=1 to n do        begin                readln(x,y,z);                s[x,y]:=s[x,y]+z;        end;        gap[0]:=m;        while f[1]<m do//直到不存在路径为止        begin                find:=false;                sum:=maxlongint;                dfs(1);        end;        writeln(ans);end.
原创粉丝点击