[转载]网络最大流SAP算法心得

SAP算法心得

网络最大流算法是网络流算法的基础,实现方法很多,但时间复杂度与编程复杂

度难于兼顾。一方面,诸如预流推进等高效算法难于编写调试,有时实际效果欠佳

(参见dd_engi的评测);另一方面,基于增广路的算法大多时间效率不高。于是许多

人选择了相对简单的Dinic算法。事实上,SAP算法更易于理解,时间效率更高,编程更简单,思路更清晰。

(名词解释)SAP(Shortest Augmenting Paths): 最短增广路

算法基本框架:

·   定义距离标号为到汇点距离的下界。

·   在初始距离标号的基础上,不断沿可行弧找增广路增广,一般采用深度优先。可行弧定义为:

{ i,j|h [i]=h[j]+1}

·   遍历当前节点完成后,为了使下次再来的时候有路可走(当然要满足距离标号的性质:不超过真实距离),重标号当前节点为:

min{h[j]|(i,j)}+1

·   重标号后当前节点处理完毕。当源点被重标号后,检查其距离标号,当大于顶点数时,图中已不存在可增广路,此时算法结束;否则再次从源点遍历。

·   理论复杂度为:

O(n2m)

我的心得:

·  理论上初始标号要用反向BFS求得,实践中可以全部设为0,可以证明:这样做不改变渐进时间复杂度。

·   理论上可以写出许多子程序并迭代实现,但判断琐碎,没有层次,实践中用递归简单明了,增加的常数复杂度比起SAP速度微乎其微却极大降低编程复杂度,易于编写调试。

·  ★GAP优化★ (性价比极高,推荐!详见程序“//GAP”部分

注意到我们在某次增广后,最大流可能已经求出,因此算法做了许多无用功。可以发现,距离标号是单调增的。这启示我们如果标号中存在“间隙”,则图中不会再有可增广路,于是算法提前终止。实践中我们使用数组vh[i]记录标号为i的顶点个数,若重标号使得vh中原标号项变为0,则停止算法。

附效率测试与比较:

算法    高标推进 SAP(GAP) Dinic SAP(NOGAP) BFS+EK

时间(s) 5.67     6.02      11.35 23.90      55.77

注:高标推进程序在180行左右。Dinic用的是dd_engi带BFS的标程,带GAP优化的SAP参见程序。

附源程序与注释(注意以下程序未用BFS,只用到递归,实现简单)

{CODE系手工打造}

//ex010901 maxflow;

const maxn=200;

var a:array[0..maxn+1,0..maxn+1] of longint;
    gap,gapv:array[0..maxn+1] of longint;
    n,m,i1,i2,t1,t2,t3,aug,flow:longint;
    flag:boolean;


procedure init;
begin
    assign(input,'ditch.in');
    reset(input);
    assign(output,'ditch.out');
    rewrite(output);
end;


procedure endln;
begin
    close(input);
    close(output);
    halt;
end;


procedure auge(p:longint);
var mingap,augt,i1:longint;
begin
    mingap:=n-1;
    augt:=aug;
    if p=n then
      begin
        inc(flow,aug);
        flag:=true;
        exit;
      end;
    for i1:=1 to n do
      if a[p,i1]>0 then
        begin
          if gap[i1]+1=gap[p] then
            begin
              if a[p,i1]<aug then
                aug:=a[p,i1];
              auge(i1);
              if gap[1]>=n then exit;
              if flag then break;
              aug:=augt;
            end;
          if gap[i1]<mingap then mingap:=gap[i1];
        end;
    if not flag then
        begin
          dec(gapv[gap[p]]);
          if gapv[gap[p]]=0 then gap[1]:=n;
          gap[p]:=mingap+1;
          inc(gapv[gap[p]]);
        end
      else
        begin
          dec(a[p,i1],aug);
          inc(a[i1,p],aug);
        end;
end;

 

begin
init;
fillchar(a,sizeof(a),0);
fillchar(gap,sizeof(gap),0);
fillchar(gapv,sizeof(gapv),0);
read(m,n);
for i1:=1 to m do
    begin
      read(t1,t2,t3);
      inc(a[t1,t2],t3);
    end;
gapv[0]:=n;
flow:=0;
while gap[1]<n do
    begin
      aug:=maxlongint;
      flag:=false;
      auge(1);
    end;
writeln(flow);
endln;
end.
Reference:

1.几种高级网络流算法的实测, dd_engi

2.Network Flows: Theory, Algorithms, and Applications, Ahuja, R.K.

3.http://www.gnocuil.cn/blog/2007/11/网络流的sap算法, gnocuil.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值