最大流与最小割问题

最大流问题
    对于一个流网络G  (V,E),其流量 f 的最大值称为最大流,最大流问题就是求一个流网络的最大流。
    增广路定理:当且仅当由当前的流f 压得的残留网络f G 中不存在增广路径时,流f 的流量f 达到最大。
   根据增广路定理,我们可以设计出最基本的求最大流的方法,一开始将流网络G  (V,E)的流 f 置为零流,即对于(u,v)E时, f (u,v)  0。然后构建残留网络,寻找增广路径增广,再修改残留网络,重复此过程,直到无法找到增广路径。

   此方法(之所以不是算法,是因为实现方法很多)称为Ford-Fulkerson 方法。

伪代码如下:
FORD-FULKERSON-METHORD (G, s, t)
1 initialize flow f to 0
2 while there exists an augmenting path p
3 do augment flow f along p
4 return f

Ford-Fulkerson 方法  (G,s,t )
1 将各边上流量 f 初始化为  0
2  while 存在一条增广路径 p
3      do 沿路径 p 增广流量 f
4  return f

假设有向网络 G 中边 (i,j) 的容量为 c(i,j) ,当前流量为 f(i,j) ,则此边的剩余流量即为 r(i,j) = c(i,j) - f(i,j) ,其反向边的剩余流量为 r(j,i) = f(i,j) 。有向网中所有剩余流量 r(i,j) > 0 的边构成残量网络 G,增广路径p即是残量网络中从源点 s 到终点 t 的路径。

沿路径 p 增广流量 f 的操作基本都是相同的,各算法的区别就在于寻找增广路径 p 的方法不同。例如可以寻找从 s 到 t 的最短路径,或者流量最大的路径。




最小割问题
最小割是指流网络中容量最小的割。
Ford-Fulkerson 定理(最小割最大流定理):在流网络中,最小割的容量等于最大流的流量。
根据这个定理,我们就可以通过求流网络的最大流来得到最小割。



几种经典最大流算法

最大流算法分为两大类:增广路 (Augmenting Path) 和预流推进重标号 (Push Relabel) 。也有算法同时借鉴了两者的长处,如 Improved SAP


EK算法(Edmonds-Karp)

在无权边的有向图中寻找最短路,最简单的方法就是广度优先搜索 (BFS),E-K 算法就直接来源于此。每次用一遍 BFS 寻找从源点 s 到终点 t 的最短路作为增广路径,然后增广流量 f 并修改残量网络,直到不存在新的增广路径。E-K 算法的时间复杂度为 O(VE2),由于 BFS 要搜索全部小于最短距离的分支路径之后才能找到终点,因此可以想象频繁的 BFS 效率是比较低的。实践中此算法使用的机会较少。


Dinic算法(构造分层网络寻找最短增广路)

首先定义分层网络 AN(f)。在残量网络中从源点 s 起始进行 BFS,这样每个顶点在 BFS 树中会得到一个距源点 s 的距离 d,如 d(s) = 0,直接从 s 出发可到达的点距离为 1,下一层距离为2 ... 。称所有具有相同距离的顶点位于同一层,在分层网络中,只保留满足条件 d(i) + 1 = d(j) 的边,这样在分层网络中的任意路径就成为到达此顶点的最短路径。

Dinic 算法每次用一遍 BFS 构建分层网络 AN(f),然后在 AN(f) 中一遍 DFS 找到所有到终点 t 的路径增广;之后重新构造 AN(f),若终点 t 不在 AN(f) 中则算法结束。DFS 部分算法可描述如下:

Dinic算法模板

#include 
#include 
#include 
using namespace std;

const int INF=2e9;

const int mm=999;

const int mn=999;

int node,s,t,edge;

int ver[mm],flow[mm],next[mm];

int head[mn],work[mn],dis[mn],q[mn];

void init(int _node,int _s,int _t)
{
    node=_node, s=_s, t=_t;
    for(int i=0;i0)
        {
            flow[i]-=temp;
            flow[i^1]+=temp;
            return temp;
        }
    }
    return 0;
}

int Dinic_flow()
{
    int ans=0,res,i;
    while(Dinic_bfs())
    {
        for(i=0;i


Improved SAP算法

通常的 SAP 类算法在寻找增广路时总要先进行 BFS,BFS 的最坏情况下复杂度为 O(E),这样使得普通 SAP 类算法最坏情况下时间复杂度达到了 O(VE2)。为了避免这种情况,Ahuja 和 Orlin 在1987年提出了Improved SAP 算法,它充分利用了距离标号的作用,每次发现顶点无出弧时不是像 Dinic 算法那样到最后进行 BFS,而是就地对顶点距离重标号,这样相当于在遍历的同时顺便构建了新的分层网络,每轮寻找之间不必再插入全图的 BFS 操作,极大提高了运行效率。国内一般把这个算法称为 SAP...显然这是不准确的,毕竟从字面意思上来看 E-K 和 Dinic 都属于 SAP,我还是习惯称为 ISAP 或改进的 SAP 算法。

 与 Dinic 算法不同,ISAP 中的距离标号是每个顶点到达终点 t 的距离。同样也不需显式构造分层网络,只要保存每个顶点的距离标号即可。程序开始时用一个反向 BFS 初始化所有顶点的距离标号,之后从源点开始,进行如下三种操作:(1)当前顶点 i 为终点时增广 (2) 当前顶点有满足 dist[i] = dist[j] + 1 的出弧时前进 (3) 当前顶点无满足条件的出弧时重标号并回退一步。整个循环当源点 s 的距离标号 dist[s] >= n 时结束。对 i 点的重标号操作可概括为 dist[i] = 1 + min{dist[j] : (i,j)属于残量网络Gf}。


你可能感兴趣的:(图论)