上两篇文章,我介绍了最短路径中的两种算法:
最短路径算法——清晰简单的弗洛伊德算法(Floyd)
最短路径算法——简单明了的迪杰斯特拉算法(Dijkstra)
这篇文章,我来简单介绍一下最大流模型!
最大流模型
\qquad
很多的数学模型往往来源于生活问题,本文介绍其中一个问题借此引出最大流模型,让读者能够更好地了解模型的背景以及应用。
\qquad
现有一管道网络用于运输原油,将原油从油井运输到提炼厂,为了在网络中顺畅地输运原油,需要在中间合适的距离安装增压泵站,每一段管道有一个有限的最大原油流量(容量),每段管道可以是单向,也可以是双向,取决于它的原始设计。那么如何确定从油井到提炼厂原油的最大流量?
\qquad
下面给定双向弧的相关概念:
\qquad
给定弧
(
i
,
j
)
(i,j)
(i,j),其中
i
<
j
i<j
i<j,用符号
(
C
‾
i
j
,
C
‾
j
i
)
(\overline{C}_{ij},\overline{C}_{ji})
(Cij,Cji)表示两个方向
i
→
j
,
j
→
i
i→j,j→i
i→j,j→i弧上的容量。为了更清晰地描述,把
C
‾
i
j
\overline{C}_{ij}
Cij放在靠近节点
i
i
i的一边,把
C
‾
j
i
\overline{C}_{ji}
Cji放在靠近节点
j
j
j的一边,如下图所示。
C
‾
i
j
表
示
从
i
→
j
的
弧
上
的
容
量
,
C
‾
j
i
表
示
从
j
→
i
的
弧
上
的
容
量
\overline{C}_{ij}表示从i→j的弧上的容量,\overline{C}_{ji}表示从j→i的弧上的容量
Cij表示从i→j的弧上的容量,Cji表示从j→i的弧上的容量
1 枚举割
\qquad 割(cut) 是一部分弧的集合,如果将这些弧从网络中删除,就会断开源点和汇点之间所有的流。割的容量等于这个割中所有弧上容量的和。在网络中所有可能的割中,最小容量的割就对应了这个网络的最大流。
例子
如下图网络,按照上述表示方法对每一条双向弧都标上了容量。例如,对于弧(3,4),从节点3到节点4的流量限制为10单位,从节点4到节点3为5单位。我直接在图中,标出了该网络的3个割:
图中3个割的容量如下表:
|
|
|
---|---|---|
|
|
|
|
|
|
|
|
|
从表中可以看出,该网络最大流不超过60个单位。枚举所有割,对于小型网络是可行的,但是对于比较复杂的网络,效率就很低了,所以需要寻找其他算法。
2 最大流算法
2.1 原理
\qquad
最大流算法的核心思想是:从网络中寻找从源点到汇点具有正的流的突破路径。
\qquad
弧
(
i
,
j
)
(i,j)
(i,j)上的初始容量
(
C
‾
i
j
,
C
‾
j
i
)
(\overline{C}_{ij},\overline{C}_{ji})
(Cij,Cji),当给定一个流并找到突破路径后,需要对每条弧上的容量进行修改,修改后的容量称为剩余容量
(
c
i
j
,
c
j
i
)
(c_{ij}, c_{ji})
(cij,cji)。 如果节点
j
j
j从节点
i
i
i接收到一个流,那么给节点
j
j
j标号为
[
a
j
,
i
]
[a_j,i]
[aj,i](节点
j
j
j的表示)。其中
a
j
a_j
aj表示从节点
i
i
i流到节点
j
j
j的量,
i
i
i表示流的来源是节点
i
i
i。
2.2 步骤
第1步: 首先将所有弧 ( i , j ) (i,j) (i,j)的剩余容量设为初始容量,即 ( c i j , c j i ) = ( C ‾ i j , C ‾ j i ) (c_{ij}, c_{ji}) = (\overline{C}_{ij},\overline{C}_{ji}) (cij,cji)=(Cij,Cji).取 a 1 = ∞ a_1=\infty a1=∞,则源点1标号为 [ ∞ , − ] [\infty,-] [∞,−]. 令 i = 1 i=1 i=1,进入第2步。
第2步: 确定集合 S i S_i Si,它是节点 i i i通过剩余容量为正的弧能够直接到达的所有未标号的节点 j j j的集合。如果 S i = ∅ S_i=\emptyset Si=∅,进入第3步;否则,进入第4步。
第3步: 确定 k ∈ S i k\in S_i k∈Si,使之满足 c i k = m a x j ∈ S i { c i j } c_{ik}= \mathop{max}\limits_{j\in S_i}\{c_{ij}\} cik=j∈Simax{cij}. 令 a k = c i k a_k=c_{ik} ak=cik,并且给节点 k k k标号 [ a k , i ] [a_k, i] [ak,i].如果 k = n k=n k=n,此时汇点(终点)得到了标号,也找到了一条突破路径,进入第5步;否则令 i = k i=k i=k,转回第2步。
第4步(回溯): 如果 i = 1 i=1 i=1,那么不存在突破路径,进入第6步;否则,令 r r r是紧邻在当前节点 i i i之前得到标号的节点,并将节点 i i i从节点 r r r的相邻节点集合中删除,令 i = r i=r i=r,转回第2步。
第5步(剩余容量的确定): 令
N
p
=
(
1
,
k
1
,
k
2
,
.
.
.
,
n
)
N_p=(1,k_1, k_2,...,n)
Np=(1,k1,k2,...,n)是从源点1到汇点
n
n
n的第
p
p
p条突破路径,则这条路径上最大流量为:
f
p
=
m
i
n
(
a
1
,
a
k
1
,
a
k
2
,
.
.
.
,
a
n
)
f_p=min(a_1,a_{k1},a_{k2},...,a_n)
fp=min(a1,ak1,ak2,...,an)
\qquad
这条路径上每条弧的剩余容量在顺着流的方向上
f
p
f_p
fp是减少的,在逆着流的方向上
f
p
f_p
fp是增加的。
\qquad
例如,对于该路径上的节点
i
i
i与节点
j
j
j,当前剩余容量为
(
c
i
j
,
c
j
i
)
(c_{ij}, c_{ji})
(cij,cji)变为:
\qquad
<\a> 如果流是从节点
i
i
i流向节点
j
j
j,则弧上的剩余容量为
(
c
i
j
−
f
p
,
c
j
i
+
f
p
)
(c_{ij}-f_p, c_{ji}+f_p)
(cij−fp,cji+fp);
\qquad
<\b> 如果流是从节点
j
j
j流向节点
i
i
i,则弧上的剩余容量为
(
c
i
j
+
f
p
,
c
j
i
−
f
p
)
(c_{ij}+f_p, c_{ji}-f_p)
(cij+fp,cji−fp);
\qquad
恢复第4步删除掉的节点,然后令
i
=
1
i=1
i=1,转回第2步接着寻找新的突破路径。
第6步(最优解):
\qquad
<\a> 给出已经找到的
m
m
m条突破路径,那么网络的最大流为:
F
=
f
1
+
f
2
+
.
.
.
+
f
m
F=f_1 + f_2 + ...+ f_m
F=f1+f2+...+fm
\qquad
<\b> 根据每条弧
(
i
,
j
)
(i,j)
(i,j)上的初始的和最终的剩余容量,
(
c
i
j
,
c
j
i
)
和
(
C
‾
i
j
,
C
‾
j
i
)
(c_{ij}, c_{ji})和 (\overline{C}_{ij},\overline{C}_{ji})
(cij,cji)和(Cij,Cji)按照下面的方法确定该弧上的最优流:令
(
x
,
y
)
=
(
C
‾
i
j
−
c
i
j
,
C
‾
j
i
−
c
j
i
)
(x,y)=(\overline{C}_{ij}-c_{ij},\overline{C}_{ji}-c_{ji})
(x,y)=(Cij−cij,Cji−cji),如果
x
>
0
x>0
x>0,那么从节点
i
i
i流向节点
j
j
j的最优流是
x
x
x个单位;如果
y
>
0
y>0
y>0,那么从节点
j
j
j流向节点
i
i
i的最优流是
y
y
y个单位.(注意
x
,
y
x,y
x,y不能同时为正数).
3 总结
\qquad
由于例子过于繁杂,这里就不做具体展示,有兴趣的读者可以参考运筹学相关书籍,这里推荐2本我觉得不错的,分别是:
《运筹学导论》 作者:[美]Hamdy A·Taha 出版社:人民邮电出版社;
《运筹学》 作者:运筹学教程编写组 出版社:清华大学出版社
|
|