网络流问题小结
问:在给定图中是否存在s->t的路径?
这个问题显然很简单,用dfs或bfs找一条。找到就存在,找不到就不存在。
存在路径时,算法找出一条路径,成功;
不存在路径时,算法失败,不存在路径仅当算法是正确的,但是没有证明过呀。
能不能给一个针对该问题的证明?
如果想证明从s->t不存路径,不妨画这样一幅图:
此时,很直观地知道,s->t无路径。
不妨先考虑什么叫存在一条从s到t的路径,这个时候,可以把所有以s开头,t结尾,节点所有的排列都写出来
:
因为不考虑节点重复,所以肯定可以写出来。
那么如果存在路径,就说明存在一个序列,其中相邻的两个节点都出现在图的边中,
所谓不存在s->t的路径,就说明每个序列中至少存在一对相邻节点不出现在图的边中。
此时分析每一个序列,就可以证明s->t没有路径。
但显然这个证明太麻烦,有没有简短的证明?
不妨看看dfs或bfs在什么时候会返回找不到路径。dfs或bfs,会从起点开始,不断寻找可以到达的点,所有可达的点会形成一个集合,命名为S,把剩下的节点放入集合T中,当算法失败是,S中不存在向T的连边,否则这将与算法的正确性相违背(从起始节点扩展到所有可以到达的节点),但是允许T到S的边。
这里就引入一个定义:有向图的ST割,所谓的割就是把所有的节点分成两个部分,要求起点s位于S中,终点t位于T中。
割的大小:S中的点向T中的点连边的个数。
下证:任意一个大小为0的ST割就是找不到路径的证据
对于一幅不存在s->t路径的中,同样列出所有以s开头,t结尾节点排列,对于每一个序列,ST割把排列分成的两个部分,其中起点s一定在S中,t一定在T中,所以在每一个序列中一定会存在一对相邻的节点,一个在S中,一个在T中,但因为割的大小为0,即不存在从S到T的连边,所以任意一个序列都可以找到一对相邻节点,它们之间的边并不存在,所以自然无法连通,s自然无法到达t!
证毕!
结论:大小为0的ST割就是“找不到路径”的证据。
之前发现,当算法失败时会产生一个大小为0的ST割,而任意一个大小为0的ST割就是找不到路径的证据,所以说算法失败时路径不存在。
加强,求不止一条路径
前导:
证明:在网络流中割的大小是不相交路径数的上界
先证当割的大小为1时,不存在2条不相交路径。
在当前网络流中,记S={s,a,b,d} , T={c,t},此时割的大小为1,即只有一条边从S到T,当列出所有从s到t的路径,都至少会经过这个割一次,假设能在左边找到两条不重复的路径,那么把这两条路径穿过割的边找出来,假设这两条边是满足条件不重复的,那么这两条边一定是不同的,这与我们找到的一个大小为1的st割相违背,所以不存在大于等于1条不相交路径。(依次类推,3条、4条、5条都一样,所以可以延伸出:当割的大小为1时,不存大于1条不相交路径。)
但是我们只是推出不相交路径小于等于1,当我们找出一个大小为0的割时,
即上图中S={s,a,b,c},T={t},且(c,t)边不存在,此时割的大小为0,不相交路径数为0,即(不大于0)。
因此如果看到图中存在大小为1的割,不能就说图中存在一条s到t的路径。
再举个例子,当在图G2中,如果我们写出所有st割,割的大小都是不小于2的,
例如令S={s,a,b,c}那么存在3条从S到T的边,继续举例可以发现割的大小都是不小于2的。通过这个例子,以此类推,我们发现割一个很重的性质,即:当我们找到一个大小为l的割,那么其实就是找到了一个从S到T不相交路径的上界。
如果找到一个大小为l的st割,那么知道不相交路径数的最大值k>=l,如果同时能在图中找到m条不相交的路径,那么此时证明了这个图上至少只有m条,即l>=m,当l=m时,就可以说明不相交路径数的最大值为l。
所以这就给了我们求最大不相交路径数思路,如果能同时找到m条不相交路径数和大小为m的s-t割,那么最大不相交路径数就等于m。(这就是解决网路流问题,以即证明网络流算法正确性的工具),把找到的不相交路径数做为最优解的下界,把割的大小做为最优解的上界,当上界=下界时,就求出最优解。
有了前导就来证明:
不妨从一个简单直观但是不正确的方法开始,试着求解图中有多少条不相交的路径,思路是能够同时找到不相交路径数是m,并且大小是m的s-t割,那么就求出了最优解。相比较而言,找路径要简单些,因为很容易使用dfs或bfs在图中找到一条路径,所以不妨设计一个贪心算法,每次在图中找到一条路径,再删掉这条路径上的边,在剩下的图中继续找路,直到找不到路径,但是显示是错误的。因为在这个简单的算法中,找到一条路径并删掉它会阻碍其他的路径选择, 但是如果有一个办法纠正之前犯下的错误,是不是就能解决找最多条不相交路径数的问题呢。答案是肯定的。
这个算法就是Ford-Fulkerson算法,这个算法在开始时任意找一条路径,但在之后寻找路径的过程中会不断纠正犯下的错误,那么纠正是这个什么过程呢?不妨用刚刚的例子看看:
假设已经犯了一个错误
此时剩下的图找不到路径了,但是显然不是最优解,此时我们希望纠正成如下所示:
那该对上面的图做怎样的改动呢?不妨把两幅图的差别画出,用红色画出需要加入的边
但是修改并不局限于加入一些边,还应该删除一些犯错误的边,如d->a边,此时将它标出,红色的边已经在原来的图上形成一条路径,这条路径由两种类型的边组成,一种是新增的边,即原图中的边,此外还可以删除一条原先走过错误的边,这看起来就是逆着原先的方向走了一步。
因此当我们想要构造一个纠正方案时,有如下操作:对于之前没有使用的边就原样保留,此外为了纠正以前犯下的错误,我们可以把之前用过的边的方向反过来, 如下图:
于是可以找到一条路径:s,a,b,t,这就可以纠正之前犯下的错误。
此时不妨把纠正路径后的图画出:
此时,在修正后的图中找不到一条从不相交路径了,算法终止。
算法终止意味着,dfs/bfs算法会返回一个大小为0的割,其中这个割的一部分就是可以从起点到的所有节点,另一部分就是剩下的所有节点,例如此时:
从S出发可以找到以s为割的一部分,剩下的为另一部分。
因为此时不存在从终点到起点的路径,因此这个割的大小一定为0。
但是虽然在这里这个图是不连通的,注意到a->s、d->s这两条边实际上是由已经找到的路径构成的,对应的他们在原来的图中是存在s->a、s->d的两条边,因此只有一个s-t割,在原图中也可以画出来,得到一个大小为2的割,因此我们的算法在纠正犯的错误以后,同时得到2条边不重复的路径,和大小为2的割,此时可以下判断,找到最优解。
而这样纠正的想法就是Ford-Fulkerson中的增广路径,刚才通过把已经走过的边反过来,所构造的新图,就是残留网络。Ford-Fulkerson就是这样一个贪心算法,它会始终维护一段当前已经找到的路径的集合,在已经找到不相交路径的基础上,构造一个残留网络,这个残留网络由两部分组成,未用过的正向边,和已经用过的反向边,因此既可以使用未使用的边,也可以逆着使用已经使用的边,从而纠正过去犯的错误。这个贪心算法每次都在残留网络上找到一条不相交路径,这条路有可能会顺着未使用的边向前走,也有可能会纠正之前犯的错误,并且相应地更新路径的集合,最后在找不到路径时结束。
这时我们对Ford-Fulkerson算法已经由了比较直观的理解,但是为什么我们在残留网络上能找到一条路径,我们就能够找到一条新路径呢?以即我们是不是在找不到路径时,就一定得到了最优解呢?以即找到了一个大小和路径数相同的割呢?这些结论都不是显然的。
接下来来理解一下残留网络,假如已经找到三条互不相交路径路径,P1、P2、P3
画出残留网络中的图,其中s内的点都是起点s,t中的点都是汇点t
这时找到一条从s出发,到t的路径,这条路径可能用到已经被用过的边和未用过的边
那么该如何修正才能加入一条新路径呢?
我们不妨重新把P1、P2、P3按照原来的方向在图上画出来,并且把残留网络中需要修正的边删掉,这时将看到,P1不变,P2、P3被截成两段,然后把刚才求得的路径在这个图上画出,就可以很自然地发现通过修正P2和P3已经得到四条路经
如此往复这个过程,我们可以采用数学归纳法(①当面对一个空图时,能找到一条边,此时显然是不相交的;②当已经有k条边且互不相交时,根据上述操作可以得到第k+1条边,同样也是互不相交的。),证明我们始终可以维护一个合理路径的集合,这些路径的集合中没有重复的边,直到在残留网络中找不到路径为止。
那么是不是算法终止时求得的路径就是最大值呢?
设最大值是k,当前求得的值是m,显然k>=m,
要想证明k=m,还需证明k<=m
即找出k的上界,此时只要找出一个大小是m的s->t割即可(因为割的值就是不相交路径的上界)。那么该怎么找呢?
很自然的,当残留网络不连通的时候,我们就能找出在残留网络中大小为0的割,不妨把上图的残留网络画出来并假设当有了当前四条路径后,残留网络不再连通,此时回顾残留网络的定义,残留网络中两种类型的边,一种是用已经求得的边反过来得到的(绿色),另一种是不在已有路径,但在原图中(蓝色)。
根据刚才的假设,此时在残留网络上已经找不到不相交路径,因此在残留网络上存在一个大小为0的割,不妨用红色把这个割画出来,
因为割的大小为0,所以一定不存在蓝色的边从S到T的边,而大小为0的割是使用dfs或bfs在找到所有可以从起点到达之后所构成的,因此在这个时候,如果我们考虑残留网络和原图的区别,他们的区别仅仅是所有绿色部分上面的边是取反的,因此如果我们能证图中绿色的边恰好都只穿过TS一次,那么因为原图是由蓝色的边和绿色的边反向构成的,那么我们就在原图中得到了一个大小是4的割。
此时利用反证法可以容易得到,假设有S和T,并且有一条绿色的路径从终点出发,到达起点,并且穿过T-S超过一次,此时发现一条从S连向T的边,这与假设“ST割的大小为0矛盾”,因此证明了bfs或dfs在残留网络上找到了一个大小为0 的割,一定对应了原图上,大小恰好等于路径数量的一个割。
从而我们证明了,在算法终止时,假设有m条路径,我们又恰好得到了一个大小为m的割,因此由上下界共同逼近,我们求得图中不相交路径的最大值。
与此同时我们发现了该算法背后的一个结论:因为任给一个S-T割,割的大小都是不相交路径的上界,如果希望用割逼近最大不相交路径的数量,就希望求出所有S-T割中最小的那个,这才是最合理的估计。因此我们要求的是所有S-T割中最小的那个。
而希望逼近的是若干个路径的集合,使得路径之间没有公共边,并且路径数最大,在这里我们用该算法同时找到了m条路径和大小为m的割,因此证明了整个图当中,最小的割就等于数量最大的路径数,这就是最大流最小割问题的离散版本。
总的来说就是先利用反向边、增广路径求出一个不相交路径数m(下界),然后通过反证法证得最终残留网络会对应一个原图中大小为m的割(上界)。上界等于下界,m就是最优解。
―――――――――――――――――――――――――――――――――――
如果边带上了权值,那么不妨把边权是5的边,拆成5条没有边权的边。
例如在下图中,我们可以构造一个与之等价的没有权值的图,运行节点之间存在重边,此时从s->a就有20条边,a->b有5条边,以此类推。
此时同样可以求从s点到t不相交路径数。如果考虑把每一条边拆开后得到的若干条路径重新画在图上,例如求得的两组从s->t的路径当中,共有15条,不妨把这5条路径经过这些边的次数写在边上,如下图:
转化成成了流的概念,所谓流网络,就是一个有s点原点、t点汇点的带权有向图。
把边上的权值成为其容量,用字母C表示。如果想要直观的理解容量这个概念,不妨把容量想象成穿过这条边路径的数量,例如在当前的网络当中,有5条路径经过a->b,由于a->b的容量是5,就不允许更多的路径穿过它。
因此不妨在这样一个流网络上把所有的路径都写出来,例如:
原则上可以写出所有从s到t的简单路径,如果希望求出尽可能多的从s到t的简单路径,并且同时不超过每一条边上的容量限制,那么此时可以为每一条路径设置一个变量,例如:
此时可以用一个线性的不等式组来解决刚才的问题,具体来说我们希望求出最多可能容纳的路径,即最大化(x1+x2+x3+...xn),对于任何一条边,不希望经过它的路径数超过容量,例如对于s->a这条边,希望(包括s->a这条边的路径前的变量相加)x1+x2+x3+...<=20,依次类推列出所有边的约数条件,并且xi>=0。此时得到网络流问题的一个线性表示,这就是一个线性规划。
但这有什么用吗,因为我们都知道,一个有向图当中,我们可能存在指数多条路径,所哟即使对一个数百数千节点这样的中小规模的图问题,此时列出不等式的数量都将非常巨大,那有什么用呢?
之际上这才是网络流问题的一个原始表达,这个概念刻画了什么是网络当中的流,也就是在容量限制之下,我们对路径进行叠加,以试图找出尽可能多的s点到t点不相交路径,这样一个原始的线性规划,虽然规模难以求解,但是可以帮助我们在接下来分析网络流的性质,此外,大家熟知的网络流问题,其实是对这样一个线性规划的简化,它放松了一个流网络是由路径组成的条件,而是不仅允许网络由路径组成,而且还允许存在环流,接下来看看大家所熟知的网络流定义,同样看下图:
此时,不再用s到t的路径来表示流,而是给每一条边假设一个变量,这个变量代表穿过这条边路径的数量,此时有一个非常重要的关卡,例如对于一条路径:s->a->c->d->t,除了起点和汇点,其它点都是进入一次出去一次,这样的性质对于所有的路径都成立,因此无论有多少条路径从s到t,对于任意一个点来说,这些路径叠加以后,进入这个点的次数=离开这个点的次数。
,每一条边经过的次数为这条边上的流量,用字母f表示,例如b->t这条边的流量记为f(b,t)。因此,一个合法路径的叠加的必要条件就是:除了源点和汇点,所有其他点输入的数量要等与输出的数量,即所有入边流量和=出边流量和,例如:
f(s,a)=f(a,b)+f(a,c)
f(a,b)+f(d,b)=f(b,c)+f(b,t)...以此类推
此时可证明,在满足这样约束条件下,从s点流出的所有流量和=流入t点的流量和,因此如果求出尽可能求出s到t的路径,就希望最大化从s流出的所有边上的流量和, 即:f(s,a)+f(s,c),此时也可写出一个线性规划:
max=f(s,a)+f(s,c)
f(s,a)=f(a,b)+f(a,c)
f(a,b)+f(d,b)=f(b,c)+f(b,t)...以此类推
但是此时的线性规划就比之前的简单多了,变量数等于图中的边数,方程数等于点数减一。
最后讲一下,网络流的原始表达还有一个结论:这个线性规划体现了网络最大流的值观含义,也就是把最大流想象成路径的叠加,并且叠加的路径不超过容量上限。而线性规划里的理论当中有一一个非常有趣的理论是对偶理论,我们总是可以针对某一个线性规划,写出一个和它的最优值完全相同的线性规划,我们只需要知道,在这个问题的线性规划中,我们不再为每一条路径设置变量,而是为每一个约束条件设置变量,
这次,从最简单的模型:证明图中路径是否存在入手,引入了割的概念,并且借助起点到终点最多多少条互不相交路径的条数引入了流,然后很细致地探寻了这样一个简化的问题上Ford-Fulkerson算法怎么样证明一个最大流和最小割定理,最后给了网络流问题一个比较严谨的定义,