费用流是网络流的一个很重要的组成部分,也是非常有用的一种图论模型,关于费用流的算法,流传比较广的主要是消圈和增广路算法,而近来炒得沸沸扬扬的ZKW算法也是一种非常优秀的算法,这里我就谈谈我对此算法的一些理解。
此算法是由ZKW创立,主要思想仍然是找增广路,只是有了一些优化在里边。原来我们找增广路主要是依靠最短路算法,如SPFA。因此此算法的时间复杂度主要就取决于增广的次数和每次增广的耗费。由于每一次找增广路是都是重新算一遍,这样似乎显得有些浪费,如果我们能够缩短找增广路的时间,那必定会大大地优化算法。
值得注意的是,在寻求最短路得过程中,设dis[i]为i到起点的距离,对于每一条由i引向j的边,必有dis[j]<=dis[i]+map[i][j];既然满足这样的恒等式,我们就可以借用KM算法的调整思想来寻求最短路,每次只走dis[j]=dis[i]+map[i][j]的路径,一旦不存在到达终点的路径,就扫描每一条边,找到最小的距离增加值,使得有至少一条新边被加入相等子图。
算法流程如下:
1.将dis数组清零,表示当前的相等子图内只有起点。
(如果存在负权边,必须要用spfa跑一遍,初始化出dis数组,下面的第二题就是这样的例子)。
2.深搜,如果到达终点,全部回退更改流量,再进行步骤2;否则,转3。
3.修改dis的值,如果无法修改,结束程序,已经找到的答案,反之转2。
据我的实际运用,ZKW费用流在二分图类的网络流图中非常快,而在稀疏图中却不是一般的慢。据我的分析,这主要是由于ZKW的增广方法是深搜,而SPFA是宽搜,这就是这两种算法最本质的区别。
下面用看一些实例:
1.最优图像
题目简述:一个n行m列的01矩阵,已知每一个位置出现1的概率,以及每一行的1的总数,每一列的1的总数,要求找出满足要求的概率最高的矩阵。
输入:
2 2
90 10
20 80
1 1
1 1
输出:
10
01
样例解释:
共有两种可能的图像:
01
10
和
10
01
前者的出现概率是0.1×0.2=0.02,后者的出现概率是0.9×0.8=0.72,故后者是最优图像。
简析:构建二分图,X集表示行,Y集表示列,由第i行向第j列引一条边,容量为1,费用为-lnx(x为概率) 。求网络的最小费用最大流。
虽然想法很好,但是实践起来不容易,因为SPFA严重地超时!
这是SPFA的时间,令人难以接收:
KW却非常快速地得出了结果
由此可见ZKW确实在二分图里比较快。
下面是ZKW较慢的一个例子:
2.BSOIer's Game
题目简述:在N*M的矩阵里,每一个格子都有一个权值,从左上角(1,1),走到右下角(N,M),只能向下或向右走,每经过一个格子,就可以获得该格子的权值,但每一个格子的权值只能计算一次(第二次经过就不算了)。要求找到从(1,1)到(N,M)的K条路径,使得总的得分最大。
简析:拆点,构造网络流图。
先将点权变为边权值,拆点变为[I,J]和[I,J]'。
从[I,J]向[I,J]’连一条容量为1,费用为A[I,J]的弧。
从[I,J]向[I,J]‘连一条容量为Max,费用为0的弧。
从[I,J]‘向[I,J+1]连一条容量为Max,费用为0的弧。
从[I,J]’向[I+1,J]连一条容量为Max,费用为0的弧。
汇点为[N,N]',新增源点为S。
从S向[1,1]连一条容量为K,费用为0的弧。
求[1,1]到[N,M]的最大费用最大流即可。
下面是SPFA的时间:
速度很快。
下面是ZKW的时间:
不尽人意,连SPFA的零头的赶不上。
因此,在使用费用流算法时,可以判断一下当前的图是稠密图还是稀疏图,如果是稀疏图,建议用SPFA,很高效,反之用ZKW,非常有利。
实例请参考(外网):P441 餐巾计划 的题解。
实例请参考(内网):P441 餐巾计划 的题解。