一、问题定义

1.1 流网络

给定有向图 G = < V , E , C > G=<V,E,C> G=<V,E,C>,其被称为流网络:

  • 容量: ∀ e ∈ E , c ( e ) ≥ 0 \forall e \in E, c(e) \ge0 eE,c(e)0
  • 流量: ∀ e ∈ E , 0 ≤ f ( e ) ≤ c ( e ) \forall e \in E, 0 \leq f(e) \leq c(e) eE,0f(e)c(e)
  • 剩余容量: ∀ e ∈ E , c ( e ) − f ( e ) \forall e \in E, c(e)-f(e) eE,c(e)f(e)
  • 总流量: ∣ f ∣ = ∑ e out of s f ( e ) = ∑ e in to t f ( e ) |f|={\textstyle \sum_{\text{e out of s}}f(e) =\textstyle \sum_{\text{e in to t}}f(e) } f=e out of sf(e)=e in to tf(e) (总流量 = 源点流出量 = 汇点流入量)

在这里插入图片描述

1.2 最大流问题

输入:

​ ①有向图 G = < V , E , C > G=<V,E,C> G=<V,E,C>,其中, c ( e ) ∈ C c(e)\in C c(e)C表示边 e e e的容量

​ ②源点 s s s,汇点 t t t


输出:

​ 总流量 ∣ f ∣ |f| f

约束目标: m a x ∣ f ∣ = m a x ∑ e out of s f ( e ) max|f|=max {\textstyle \sum_{\text{e out of s}}f(e)} maxf=maxe out of sf(e)
​ 约束条件:
\quad 容量限制: 0 ≤ f ( e ) ≤ c ( e ) 0\leq f(e)\leq c(e) 0f(e)c(e) (边上的流量不能超过容量)
\quad 流量守恒: ∑ e in to v f ( e ) = ∑ e out of v f ( e ) {\textstyle \sum_{\text{e in to v}}f(e)} = {\textstyle \sum_{\text{e out of v}}f(e)} e in to vf(e)=e out of vf(e) (每个顶点进入和流出的流量和相等)



二、算法策略

2.1 算法引入

直观想法:

①对 ∀ e ∈ E \forall e \in E eE,初始化流量为 f ( e ) = 0 f(e)=0 f(e)=0

②寻找一条源点 s s s到汇点 t t t的路径 P P P,此路径上的每条边 e e e均满足 f ( e ) < c ( e ) f(e)<c(e) f(e)<c(e)

③按路径 P P P上最小剩余容量增加路径流量

④迭代寻找路径 P P P直至无法增加路径流量

例如,在下述所给流网络 G G G中,选择红线路径作为路径 P P P,并增加了11的流量:

在这里插入图片描述

如此迭代寻找 P P P,便可以得到解。

但是,显然该方法并不可以得到最优解,例如,当该流网络为如下状态时,

我们发现,按照直观策略,该网络不能再增加流量。但是如果我们稍作调整,

在这里插入图片描述

如此,我们便成功将网络的流量增加了1。

我们不妨观察一下,我们做了什么样的改动:我们将流量进行了重新分配,缩减了某些边 ( v 2 , v 3 ) (v_2,v_3) (v2,v3)的流量,并将其重新分配到别的边 ( v 2 , v 4 ) (v_2,v_4) (v2,v4)上,实际上,上述变动可以看作我们沿着下图中红色路径走了1个流量:

在这里插入图片描述

也就相当于,我们引入了一条返向边 ( v 3 , v 2 ) (v_3,v_2) (v3,v2),并发现,如果我们寻找路径时允许反向搜索,则可以增大总流量。

一旦引入了反向边,就需要考虑反向边的权重问题,如何定义正向边及反向边的权重以保证流量调整合理呢?做出以下规定:

反向边权重:描述可缩减流量的上限,即原始边上的流量 f ( e ) f(e) f(e)

正向边权重:描述可扩充流量的上限,即原始边上的剩余容量 c ( e ) − f ( e ) c(e)-f(e) c(e)f(e)

如此,由一条原始边可以生成两条正向、反向边,实现反向搜索,以此来帮助我们更好地寻找到使得总流量增加的路径 P P P

2.2 一些概念

接下来介绍几个概念,并按照上述思路,介绍Ford-Fulkerson算法。

2.2.1 残存网络

对于给定流网络 G = < V , E , C > G=<V,E,C> G=<V,E,C>和流量 f f f,可以得到残存网络 G f = < V , E f > G_f=<V,E_f> Gf=<V,Ef>,其中 ∀ c f ( e ) ∈ E f \forall c_f(e) \in E_f cf(e)Ef,其残存容量为:
c f ( e ) = { c ( e ) − f ( e ) e 为正向边 f ( e ) e 为反向边 c_f(e)=\left\{\begin{matrix}c(e)-f(e) & e为正向边\\ f(e)&e为反向边 \end{matrix}\right. cf(e)={c(e)f(e)f(e)e为正向边e为反向边
残存网络中存储的是容量信息(可扩充及可缩减上限),可以帮助我们快速地发现增广路径(包含返向边的路径)。

例如:

在这里插入图片描述

2.2.2 增广路径

给定流网络 G = < V , E , C > G=<V,E,C> G=<V,E,C>和流量 f f f,增广路径 p p p是残存网络 G f G_f Gf中一条从源点 s s s到汇点 t t t的简单路径(路径上顶点不重复)。

例如:

在这里插入图片描述

如果在残存网络中存在增广路径,则说明存在流量的进一步调整方式。

2.2.3 增广路径的残存容量

增广路径的残存容量指的是一条增广路径 p p p上各边残存容量的最小值,即$c_f§=\min\left { c_f(e)|e\in p \right } $

在这里插入图片描述

增广路径的残存容量实际上就是沿着该路径流量扩充的最大值。


2.3 Ford-Fulkerson算法

接下来只需要对我们的只管策略做一些改动,便可以得到Ford-Fulkerson算法:

①对 ∀ e ∈ E \forall e \in E eE,初始化流量为 f ( e ) = 0 f(e)=0 f(e)=0

②构造残存网络 G f G_f Gf,寻找源点 s s s到汇点 t t t的增广路径 p p p

③按增广路径 p p p的残存容量增加路径流量

④迭代寻找路径 p p p直至无法增加路径流量

接下来以一个实例来展示该算法:

①流网络 G G G初始化,构造残存网络 G f G_f Gf

在这里插入图片描述

②在残存网络 G f G_f Gf中找到一条增广路径,并按照其容量更新流网络 G G G

在这里插入图片描述

③更新残存网络 G f G_f Gf

在这里插入图片描述

④重复②③:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

⑤不能找出增广路径 p p p,算法结束:

在这里插入图片描述


2.4 算法分析

该算法的伪代码如下:

在这里插入图片描述

复杂度分析:

  • 初始化阶段: O ( E ) O(E) O(E)

  • 寻找增广路径:残存网络最多有 2 E 2E 2E条边,且 O ( V ) ≤ O ( E ) O(V)\leq O(E) O(V)O(E),使用DFS,可以在 O ( V + 2 E ) = O ( E ) O(V+2E)=O(E) O(V+2E)=O(E)的时间内找到增广路径

  • 找增广路径残存容量: O ( E ) O(E) O(E)

  • 更新流: O ( E ) O(E) O(E)

在这里插入图片描述

每次循环后,流的值至少会增加1,所以循环最多执行 ∣ f ∗ ∣ |f^*| f次,算法的时间复杂度为 O ( E ∣ f ∗ ∣ ) O(E|f*|) O(Ef)

实际上,该算法的运行时间主要受限于增广过程,对于同一个流网络 G G G,不同增广路径的选择,会对结果产生巨大的影响,例如:

在这里插入图片描述

每次循环后,流的值至少会增加1,所以循环最多执行 ∣ f ∗ ∣ |f^*| f次,算法的时间复杂度为 O ( E ∣ f ∗ ∣ ) O(E|f*|) O(Ef)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐