【算法•日更•第三十四期】最大流算法
▎写在前面
在之前,我们已经清楚了网络流与最大流是什么,以及增广的操作。
如果你还不会请点击学习。
▎基本思路
先放上一张图,要不然感觉有点空旷。
下方文字请结合上面的图片食用。
先来弄清楚一个概念:容许流,就是从源点到汇点的流,显然,一个图中的容许流不是唯一的,而最大流就是流量最大的容许流。
我们先假设S是源点,T是汇点,为了寻找S到T的最大流,我们应该不断尝试寻找增流路径,增加容许流的流量,知道无法增加为止。这也被称为增广过程。
▎Ford-Fulkerson标号算法
还是上面的图。
我们对于一条边,记录三个值:这条边的容量,已用容量,剩余可用容量(不断增广时会消耗容量)。同时,再增加一个叫做反射弧反向弧的东西,初始全部为0,用于存储一条边(u,v)的逆向边(v,u),虽然不存在,但是可以用于反悔,以便于保证枚举到每一种情况。反向弧虽然名字特殊,但是我们把它视作普通的边。
这个算法既然叫作标号算法,那么一定是要标号的,对于每个点,都会有两个标号:第一个是前驱(也就是从那里过来的),第二个是当前路径上的最小边权。
这个算法本质上就是不断搜索,从S标号(无,inf)开始,不断扩展(权值为0的边不选择),到达另一个点,继续标号,如果到达了T,那么最大流加上第二个标号。而前驱的作用则是回溯,把路径上的边全部都减去该路径上的最小边权,同时该边的反向弧也增加最小边权。直到T无法再次被标号,则当前得到的容许流就是最大流。
▎算法图解
首先放个图:
然后从s开始标号。
然后随便挑一条,走到1号点的位置,然后标号。
接着走到T。
然后发现已经到达了T,T已经被标过号了,于是最大流加1。
然后返回,我们会发现(1,T)这条边减去1之后就是0了,那么为了简洁,我们就可以把它视作没有了,再添一条反向弧。(S,1)也是同理。
接着我们用刚才的方法遍历S -> 2 -> T这条路径。
发现标号了T,那么回溯,并且最大流加4。
于是我们就发现无法标号T了,那么此网络的最大流就是1+4=5了。
▎算法的正确性
虽然无法直接理解这个算法到底为什么正确,但是该有的条件它均已满足:
①每条边的长度都不可能是负数。
②每次增广时,都能保证每个点流量平衡。
③每一次S的出流量和T的入流量都变化相同。
④只要最大流是有限的,那么一定会在有限的时间内求出(不会死循环)。