网络流的SAP算法

 

网络流的最短增广路算法
在网络流问题中,最常见的方法是Ford-Fulkerson方法。这种方法每次找出一条残留网络中的增广路径并进行增广。整个算法运行过程满足流的三个性质(容量限制、反对称性、流守恒性)。与此相对的预流推进算法不满足流守恒性。在Ford-Fulkerson方法中,如何寻找增广路径是影响算法效率的主要因素。一种好的思想是每次寻找长度最短的路径。按照这种思想,如果采用BFS寻找增广路径,时间复杂度为O(n*m^2),效率不能令人满意。本文介绍一种最短增广路算法(Shortest Augmenting Path Algorithm),它的复杂度为O(n^2*m)。在实践中,这种算法效率还是比较高的。另外,著名的DINIC算法也与此算法有着密切联系。

SAP算法中,我们定义每个顶点的距离标号(Distance Labels),即残留网络中这个点到汇点的距离。然后,我们只在距离标号相邻的点间寻找增广路径。如果从一个点出发没有容许边,就对重标记并回溯(类似预流推进)。首先介绍一些定义:
残留容量:容量-流量。即,残留容量r[i,j]=c[i,j]-f[i,j]。如果只求流值,则在网络流算法中只需记录残量,而不必记录容量和流量。
残留边、残留网络:有残留容量的边成为残留边,由网络的点集、残留边集构成残留网络。
距离标号 :对于每个点i,定义其在当前残留网络中到汇点的距离为d[i]。如d[t]=0。
容许边:当且仅当r[i,j]>0且d[i]=d[j]+1时,边(i,j)是容许边。我们的算法只考虑容许边。

算法的一开始,我们从汇点进行一次BFS求出距离标号。然后从源点开始递归操作。对于一个点i的操作,如果存在容许边(i,j),当j是汇点时增广并从源点开始递归,否则就令i是j的前驱,并递归j。否则对i重标号,使得d[i]=min{d[j]}+1 ( r[i,j] )>0,并回溯。当d[s]>=n时算法停止,此时不存在任何一条增广路。为提高效率可以改递归为迭代。可以参考一下《Network Flows: Theory, Algorithms, and Applications》中的伪代码:

01. algorithm shortest augmenting path;
02.   begin
03.     x:=0;
04.     obtain the exact distance labels d(i);
05.     i:=s;
06.     while d(s)<n do
07.       begin
08.         if i has an admissible arc then
09.           begin
10.             advance(i);
11.             if i=t then augment and set i=s
12.           end
13.         else retreat(i)
14.       end;
15.   end;
16.   
17. procedure advance(i);
18.   begin
19.     let (i,j) be an admissible arc in A(i);
20.     pred(j):=i and i:=j;
21.   end;
22.   
23. procedure retreat(i);
24.   begin
25.     d(i):=min{d(j)+1: (i,j)∈A(i) and r[i,j]>0};
26.     if i<>s then i:=pred(i);
27.   end;
28.   
29. procedure augment;
30.   begin
31.     using the predecessor indices identify an augmenting path P from the source to the sink;
32.     δ:=min{r[i,j] : (i,j)∈P}
33.     augment δ units of flow along path P;
34.   end;

同样类似预流推进,我们有一个重要优化:间隙优化。即我们定义numb(k)是距离标号为k的点的个数。在重标记点i时,我们检查numb(d[i])。若numb(d[i])减为0,算法马上结束。我们很容易发现,点i被重标记则其距离标号必然小于n。而此时不存在此标号的顶点,则容许网络中必然不存在一条增广路径,因此算法结束。这个优化使得算法效率显著提高。

容易证明,SAP的复杂度为O(n^2*m)。而如果采用动态树,复杂度降为O(nmlogn)。只是动态树太过复杂。

提一下DINIC算法:
DINIC算法与SAP十分相似。只是,SAP只是开始进行一次BFS,每次只对单个顶点重标号。而DINIC不对单个顶点重标号,而是多次BFS计算标号。我们套用SAP算法并稍微修改:在过程retreat(i)中,不改变d[i],而是标记i为阻塞的。而容许边(i,j)的定义,其中j必须未阻塞。当源点阻塞,此时形成阻塞流,我们就进行一次反向BFS求得距离标号。由于每次BFS源点的距离标号单调递增,当它大于等于n时算法结束。

p.s.您可以无视本文,直接翻开《Network Flows: Theory, Algorithms, and Applications》(Ahuja, R.K.)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值