例如:有一个自来水管道输送系统,起点是S,目标是T,图中经过的管道都有一个最大的容量:
网络流的定义
在有向图G=(V,E)中:
1、有唯一的一个源点S(入度为0:出发点)
2、有唯一的一个汇点(出度为0:结束点)
3、图中的每条弧(u,v)都有一个非负的容量c(u,v)
满足上述条件的图G称为网络流图。
记为:G=(V,E,C)
可行流
每条管道中可以通过的流量。
最大流
在所有的可行流中,流量最大的一个流。(最大流可能不止一个)
解决最大流的问题常用到Ford-Fulkerson方法(在此方法下,存在着若干种不同时间复杂度下的实现)
Ford-Fulkerson和Edmonds-Karp
1、残存网络
第一个图是流网络,边上的12/16,12指的是流量,16是容量。
第二个图是残存网络,可能会存在一对相反的边,如刚刚12/16在残存网络中,体现为 v1->s = 12,s->v1 = 16-12。与流网络中对应的边代表的是该边的残余容量,流网络中不存在的边是一条反向的已有流量边,这部分流量可以通过回流减少。(残存网络中值为0的边不画出)
2、增广路径
假如有这么一条路,这条路从源点开始一直一段一段的连到了汇点,并且,这条路上的每一段都满足流量<容量,注意,是严格的<,而不是<=。那么,我们一定能找到这条路上的每一段的(容量-流量)的值当中的最小值delta。我们把这条路上每一段的流量都加上这个delta,一定可以保证这个流依然是可行流,这是显然的。这样我们就得到了一个更大的流,他的流量是之前的流量+delta,而这条路就叫做增广路。
3、方法
我们不断地从起点开始寻找增广路,每次都对其进行增广,直到源点和汇点不连通,也就是找不到增广路为止。当找不到增广路的时候,当前的流量就是最大流,这个结论非常重要。
寻找增广路的时候我们可以简单的从源点开始做bfs,并不断修改这条路上的delta量,直到找到源点或者找不到增广路。
4、代码
1 | int c[MAX][MAX]; //残留网络容量 |
1 | int dfs(int u,int t,int f) |
1 | --* |
最小割
就是从图G(V,E)中去除一些边,使得图G中源点S到终点T不连通。如果去除的这些边的权和最小,就是最小割。这个权和可以证明等于网络的最大流量!因此,最大流等价于最小割。求解最大流问题,也可以转化为最小割。求最大流和求最小割集是两类不同的算法。求解最小割集普遍采用Stoer-Wagner算法。
Stoer-Wagner
1 | int min_cut(int now) |