- 在线时间
- 0 小时
- 最后登录
- 2006-4-9
- 注册时间
- 2004-12-27
- 听众数
- 2
- 收听数
- 0
- 能力
- 0 分
- 体力
- 252 点
- 威望
- 0 点
- 阅读权限
- 20
- 积分
- 93
- 相册
- 0
- 日志
- 0
- 记录
- 0
- 帖子
- 35
- 主题
- 11
- 精华
- 0
- 分享
- 0
- 好友
- 0
升级   92.63% 该用户从未签到
 |
<TABLE height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>$ e4 C4 d( k5 D
' N9 Q* `/ E1 h' v5 `9 a; M& d% H
<TR># m/ M) Y9 W) R# r# A
<TD width=74><IMG src="http://www.frontfree.net/articles/pages/0000000554/title.gif" border=1></TD>1 I j; B, I, L
<TD vAlign=top width="100%">
) O2 h0 ?8 L; g; l5 M<TABLE height="100%" cellSpacing=0 cellPadding=0 width="100%" border=0>
% e, T" ]1 @& O2 |
+ n$ ^8 X; O1 l: w$ q$ f7 v: \<TR>0 d7 i9 w# a. c3 o) q, m
<TD class=artitle vAlign=top colSpan=2>网络流概念及相关算法介绍</TD></TR># ^& d' x9 }1 y; ^7 E3 q
<TR vAlign=top>
; W& T+ k Y s4 [* ^$ [<TD align=left>原创:怒火支袍 </TD>) }8 T. ^. i7 t/ z# w8 U4 w
<TD class=text vAlign=top align=right>2003年6月17日 </TD></TR></TABLE></TD></TR>
- F! L; M! ]+ A* |* n* D6 p<TR>
5 w8 x; M- T8 S% Z" O<TD class=arcontent colSpan=3>
( M% S7 a0 [+ R: n( r4 \; L( x
9 }7 n, e* ]0 @$ b m4 k$ W0 H<STYLE type=text/css>9 O6 ^2 ]6 r9 x4 T1 D2 n+ F: F8 W
<!--; B, T" e. M, X% U3 X
.titletxt {
# k5 d* |0 y# H, J9 u/ E font-size: 18px;) y6 @' ^( \( M9 G9 G+ E
}
' k& o/ j- Y& g1 l.tabletxt {$ N% T8 L$ y U- F
font-size: 14px;$ c# f, @% G! u9 y# L
padding: 7px;# _6 a ?! U/ A! P& ~5 S
}, n6 g9 N2 z3 @9 p P* K
--> ]! l' R7 q7 N
</STYLE>3 h* T- M( W) s, }! P
/ u6 r5 W; A. d3 ?< ><b>一、引言</b></P>
9 x$ z" L. `& M( P< align=left>如同我们可以把一个实际的道路地图抽象成一个有向图来计算两点之间的最短路径,我们也可以将一个有向图看作一个流网络来解决另一类型的问题。流网络比较适合用来模拟液体流经管道、电流在电路网络中的运动、信息网络中信息的传递等等类似的过程。</P>% A! s4 ?+ u# J4 Z ^
< align=left><b>二、网络流和最大流问题; _# s( g; `5 c7 v* p
</b>
4 T4 @/ S7 x; W& q参看下图,给定一个有向图G=(V,E),把图中的边看作管道,每条边上有一个权值,表示该管道的流量上限。给定源点s和汇点t,现在假设在s处有一个水源,t处有一个蓄水池,问从s到t的最大水流量是多少,类似于这类的问题都可归结为网络流问题。</P>
0 |7 y- C5 P; M& @3 @0 V- I, c< ><IMG src="http://www.frontfree.net/articles/pages/0000000554/pic01.gif"></P>
& C, Z9 h4 \. p) e7 v: ~< align=left>在流网络中,每条有向边可以被看导管。每根导管有一个固定的容量,代表物质流经这个导管的最大速率,例如一个管道每小时最多能流过200加仑液体或者一根电线最多能承载20安培的电流。流网络中的顶点可以看作是导管的连接处。除了源点和汇点之外,物质流进每个点的速率必须等于流出这个点的速率。如果我们把研究的物质特化为电流,这种“流的保持”属性就好像电路中的基尔霍夫电流定律一样。</P>
& [7 x6 l/ M# V/ z< align=left>下面我们用数学语言来进行相关概念的定义:
7 |4 q8 n6 H- M: v9 N! Z
X( l' m1 _3 h: {+ Y6 U设G=(V,E)是一个流网络,设c(u, v)>=0 表示从u到v的管道的流量上限。设s为源,t为汇。G的流是一个函数f: V×V →R,且满足下面三个特征:</P>4 b4 o9 \2 t' p% P% Z8 T) L9 q% F
<TABLE cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>. o5 G) T/ O4 t+ p
* F1 k( d8 m( K4 I
<TR>
2 P; u) \4 N9 A$ E, {" P- p; B<TD class=tabletxt width="2%" bgColor=#e0e0e0>1. </TD>
( q) w: D. D! F/ n6 \: L<TD class=tabletxt width="98%" bgColor=#ffffff>容量限制:对于所有的 u,v ∈ V, 要求f(u, v) <= c(u, v) </TD></TR>
$ x: v. o0 p' [( `<TR>
6 X& ?! w( Z; k<TD class=tabletxt bgColor=#e0e0e0>2. </TD>) ]2 V7 n+ G9 P# `, V
<TD class=tabletxt bgColor=#ffffff>斜对称性:对于所有的 u,v ∈ V, 要求f(u, v) = - f(v, u)</TD></TR>
. @$ I+ k9 }4 G! A+ q) f# | p. d<TR>; Y2 l/ _/ M( [1 Y u; V
<TD class=tabletxt bgColor=#e0e0e0>3.</TD>' a9 q# ~4 b0 l1 ?* M2 i
<TD bgColor=#ffffff>
; |% J* y @$ J- a' H" l< >流的保持:对于所有的 u ∈ V - {s, t},要求:∑ f(u, v) = 0(v∈V)
: x( [) @+ F+ }1 h* S: p- j: Uf(u,v)称为从结点u到v的网络流,它可以为正也可以为负。流 f 的值定义为:|f| = ∑ f(s, v)(v∈V)即从源出发的所有流的总和。</P></TD></TR></TABLE>3 \: f e7 Q" W2 m0 e; u! D5 O4 V. h
< align=left>最大流问题就是找出给定流网络的最大流。网络流问题可以归结为一类特殊的线性规划问题。</P>
; q1 Z$ M% D* v* H8 t< align=left><b>三、解决最大流问题常用算法一览</b></P>7 T9 _0 L+ u- R- L/ K' @
< align=left>解决最大流问题的常用到Ford-Fulkerson方法,之所以称其方法而不是算法,是因为在这种思想下包含着若干种时间复杂度不同的实现,其中较多地是使用Edmonds-Karp算法。与此相对,Push-relabel算法采用了与Ford-Fulkerson方法完全不同的思考角度,降低了渐进意义下的时间复杂度。而relabel-to-front算法则是对Push-relabel算法的改良和精炼,效率更佳。</P>: Y8 O9 H* R# I1 k. C; U4 Q
< align=left>关于这三种常用算法的时间复杂度可见下表:(其中V表示图的顶点数,E表示边数)</P>! q! S9 c% _1 P' d1 ?
<TABLE cellSpacing=1 width="100%" bgColor=#000000 border=0>
4 {! n7 Z' u+ q' D/ w& S$ o6 O; X' I2 |# e
<TR bgColor=#e0e0e0># ?# t$ t3 a: k1 G
<TD class=tabletxt width="25%">
( O: Q. B3 n9 k# L( H& ~ Q3 g<DIV align=center>算法名称</DIV></TD>
: V% S/ @& ~( M2 `& ^<TD class=tabletxt width="23%" bgColor=#ffffff>$ W; f1 G0 O3 h" m' t) U: r% x5 D
<DIV align=center>Edmonds-Karp算法</DIV></TD>* C, h# f8 _! _
<TD class=tabletxt width="26%" bgColor=#ffffff>
, {$ _$ D2 ?. c/ L" b+ ]& g& [<DIV align=center>一般性的push-relabel算法</DIV></TD>8 h9 a1 D+ Y7 |8 G% w+ A: z' D
<TD class=tabletxt width="26%" bgColor=#ffffff>& Y' c5 }; S) ?6 ]4 `* f, j6 s
<DIV align=center>relabel-to-front算法</DIV></TD></TR>& [7 L/ N. ^$ J0 x2 ^, y! T7 `
<TR bgColor=#e0e0e0>
' l# r2 y$ \9 [<TD class=tabletxt width="25%">0 A" z; n$ l/ h r
<DIV align=center>时间复杂度</DIV></TD>. T% s ]/ t }7 E0 F7 Q
<TD class=tabletxt width="23%" bgColor=#ffffff>
) ^$ G/ d( d5 V7 F8 _<DIV align=center>O(V*E^2)</DIV></TD>3 [6 l t2 F/ A/ Q5 ?8 m# y; c# A
<TD class=tabletxt width="26%" bgColor=#ffffff>
; Y# v8 e u, }- [6 h" \8 [<DIV align=center>O(V^2*E)</DIV></TD>; [/ B* {5 o6 Q5 B% o+ k
<TD class=tabletxt width="26%" bgColor=#ffffff>) B( g8 \8 P2 w0 e% ]5 N
<DIV align=center>O(V^3)</DIV></TD></TR></TABLE>
6 f! r4 T' F# F4 m< align=left>可以看出,当给定的有向图比较稀疏时,三种算法的效率不会相差太多,但当网络稠密时,relabel-to-front算法在效率上有着明显的优势。7 O# }2 ]5 E) ~9 o
<b>
2 s5 b: f7 x' M$ S</b><b>四、基于Ford-Fulkerson方法的Edmonds-Karp实现</b></P>) n1 i* s) S/ F5 j _: K
< align=left>一般的Ford-Fulkerson方法具有迭代性质,我们把顶点u和v之间的流记作f(u,v)。那么在最开始,我们对所有的u,v∈V置f(u,v)=0。在每次的迭代过程中,通过找到一条增加路径来使|f|增加。在这里,我们可以简单地认为所谓的“增加路径”就是一条可以传送比当前更多流的从源点s到汇点t的路径,一旦找到了这样的路径,我们就可以得到一个比原流数值更大的新流。重复这个过程,直到不存在增加路径为止,这就是Ford-Fulkerson方法的主要过程,可以用伪码表示如下:</P>( f5 Y5 V! G6 o1 u J
<TABLE cellSpacing=4 cellPadding=0 width="100%" border=0>
7 [, b7 }% s6 ]# I. K! _9 q4 b/ V( ~: D: ^; J G
<TR>4 h, R9 G# ?! k2 @: _% W3 S) d( x H
<TD bgColor=#e0e0e0>
# Y/ R1 C: w2 q; ~< align=left>FORD-FULKERSON-METHOD(G,s,t)
; O' @( m% T/ P2 f* t1 @+ {0 t* g/ A( o9 H. G0 u/ a- W. C, ~& c5 i
将流f初始化为0; A: g3 p8 ~! q5 W B) `" O
. z9 _& K6 c9 u8 q5 u
while 存在一条增加路径p
G" J' t) ^7 d8 ~
, S, s# Q0 {7 r) s& ado 顺沿p增加f# I- E1 l7 s4 K" J# \5 ^& F; F
. {' w+ ]* c3 A) Greturn f</P></TD></TR></TABLE>
6 ~7 t5 T" t* l1 _2 w4 i3 q< align=left>实现Ford-Fulkerson的时间复杂度主要取决于如何寻找增加路径p。Edmonds-Karp实现正是通过采用了广度优先的搜索策略得以使其复杂度达到O(V*E^2)。</P>
3 v' |( z5 p3 L" \. g) |( c7 K2 R9 y* H< align=left>由于这种算法的效率不很理想,我们在此不多着墨,而主要介绍下述push-relabel算法的思想。</P>+ D U! c$ N9 W( m; r* Q
< align=left><b>五、一般性的push-relabel算法</b></P>: [) _, n+ B# g: H% x- D/ F8 ?& q
< align=left>很多渐进意义下最优的算法都是采用了push-relabel算法的思想,而且很多其他的相关问题,比如最小费用流问题,也可以用这种方法很好的解决。首先介绍的是一般性的push-relabel算法。</P>* x, f# [& J! ^3 z: Q' {1 l
< align=left>不同于Ford-Fulkerson方法在残留网络中寻找增加路径的方式,push-relabel算法在运行的过程中只关注某一个顶点以及它的相邻顶点,在这个过程中,它并不像Ford-Fulkerson方法保持着“流的保持”性质,而是以一个“先流”进行运作。这个先流同样是一个 V×V →R的函数,满足容量限制和斜对称性,同时,它对所有的u∈V-{s}满足f(V,u)>=0。我们记e(u)=f(V,u)。如果e(u)>0我们就说顶点u溢出。</P>& T5 E- f, \4 }- G' Z; p
< align=left>为了步入正题,我们还需要介绍push-relabel算法引入的一个额外的高度函数。设G=(V,E)是一个流网络,源点是s,汇点是t,f是G中的一个先流。如果函数h:V→N满足h(s)=|V|,h(t)=0,而且对残留网络中所有的边(u,v)有h(u)<=h(v)+1,那么称h是一个高度函数。</P>
# o" H/ H# O0 u< align=left>正如其名称一样,push-relabel算法有两个基本操作:push和relabel。一般性的push-relabel算法就是通过往复执行这两种操作完成的:</P>+ K+ X6 x+ R0 K' d/ {
<TABLE cellSpacing=4 cellPadding=0 width="100%" border=0>5 v5 X# @ R$ w* \2 O
# W7 w. k! z. X. h) p: v<TR>
! _5 ^5 {1 `1 W3 |7 u<TD bgColor=#e0e0e0>
& `& h5 j7 R6 y< align=left>GENERIC-PUSH-RELABEL(G)
& G: a# R0 r8 ~6 n' p
/ W* x( H* P/ R+ e先流初始化
( L8 ~( D5 }" ~5 A2 k: K$ \# W* }% B/ k
while 存在可以执行的push或relabel操作2 v: H3 o! u7 g. f' a! z, }# O% k
( \: D: ?, M) Z' d+ V ]; k
选择一个可以执行的push或relabel操作执行</P></TD></TR></TABLE>
) T2 i; I9 p `< align=left>下面具体介绍一下这两个基本操作。</P>
4 j% I! ~$ m# y9 p( ^, A<TABLE cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>. I8 q% w5 s' p
6 i1 o, ]" ]$ m! Y7 L8 J
<TR bgColor=#ffffff>3 m( k7 R5 V# G
<TD class=tabletxt width="5%" rowSpan=3><b> USH(u,v)</b></TD>
& U8 E( b5 y- P8 S& u9 C9 N<TD class=tabletxt width="95%">可以执行的时机:顶点u溢出,u、v之间的残留容量cf(u,v)为正,且h=h[v]+1</TD></TR>
$ F& }2 K6 F# q6 v/ o7 N<TR>
) D7 b( Y& v1 V- h+ \) \<TD class=tabletxt bgColor=#ffffff>动作描述:将df(u,v)=min(e,cf(u,v))个单位的流从u压向v</TD></TR>+ {4 ]5 t* E9 Z% b
<TR>" p1 d) n# O) G. B; e! _
<TD bgColor=#e0e0e0>+ V1 g4 z) B* ~; d/ F
< align=left>具体步骤:
( y4 P+ v" y/ Q1 e5 }( Y. e, O" r3 T) w. \1 _
df(u,v)=min(e,cf(u,v))
3 M' E, Z8 l' z& P/ i$ Y% f a$ [4 h( O
+ C" V# Y0 M1 K7 |f[u,v]=f[u,v]+df(u,v)
0 x, H( g8 T/ j) \2 E2 F
9 G. i( @3 @6 x, N3 I; K5 ?( H$ {f[v,u]=-f[u,v]
1 Z: R0 n! h) i. T. w. d. H" l! \
e=e-df[u,v]( f* a1 i* P: d3 V# M7 j' w A
' l+ R Z4 ~" L: Y/ w6 G# Pe[v]=e[v]+df[u,v]</P></TD></TR>* I. J/ G; _! \, T1 q2 s* X P' p
<TR bgColor=#ffffff>
- Y( K$ n9 S p x# h<TD rowSpan=3>
2 n& I0 H/ G+ O( e9 x< align=left><b>RELABEL(u)</b></P></TD>
1 e' \! X! t1 e3 _: ~* g5 X<TD class=tabletxt bgColor=#ffffff>可以执行的时机:u溢出,且对所有的残留网络中的边(u,v),有h<=h[v]</TD></TR>. i- n) }+ r/ r0 x! w
<TR>
& q3 P9 R1 m! {/ L7 s<TD bgColor=#ffffff>8 z) s: E8 Z/ M @. Z
< align=left>动作描述:增加u的高度</P></TD></TR>8 z9 t! N/ d0 }8 O' \
<TR>$ \% {& y( @" Y, t6 \
<TD bgColor=#e0e0e0>
# `' N2 ^# ^. `% p* c W j1 H< align=left>具体步骤:
+ }7 e8 D v5 k; u
! f# k7 c2 `' l) ]h=1+min{h[v] u,v)是残留网络中的边}</P></TD></TR></TABLE>9 f# R, H9 E! r
< align=left>通过证明,在一般性的push-relabel算法执行过程中,relabel操作的执行次数小于2|V|^2,push操作的执行次数小于2|V||E|+4|V|^3+4|E||V|^2,而每个relabel操作的耗时在O(V)级,每个push的耗时在O(1)级,选择一个可以执行的操作也可以在O(1)内完成,因此,存在具体的实现使得一般性的push-relabel算法时间复杂度达到O(V^2*E)。</P>7 Y R+ E6 a4 k8 B5 M3 L i" {
< align=left><b>六、relabel-to-front算法</b></P>8 m: ]& i" W. w6 u- x, F, G9 T
<P align=left>通过引入邻接表和许可边的概念,relabel-to-front算法在push-relabel算法的基础上进一步提升了效率,使时间复杂度可以达到O(V^3),但是该算法的步骤和证明的过程比较繁琐,在这里就略去了,有兴趣的读者可以参考《算法导论》。</P>
: n9 d# v$ \/ d$ `* h<P align=left><b>七、二部图的最大匹配与网络最大流的关系</b></P>
/ w5 K) D) N* I6 j* u) s2 s<P align=left>有一定离散基础的读者应当对二部图的最大匹配不陌生,但它和网络流之间有什么具体的联系呢,请看下图:</P>9 k, o; S5 I, t0 b, b
<P><IMG src="http://www.frontfree.net/articles/pages/0000000554/pic02_02.gif"></P>( f/ n U7 V F. ^' i$ ^. h$ r5 B9 l
<P><IMG src="http://www.frontfree.net/articles/pages/0000000554/pic02_01.gif"></P>
R6 b- k2 ]$ V' f$ I<P align=left>是的,如果我们设二部图两部分的点集分别为L与R,现在添加源点s和汇点t,对所有的v∈L添加有向边(s,v),再对所有的v∈R添加有向边(v,t),再将原二部图中所有的无向边改为自L中的点指向R中的点的有向边,就构造了一个流网络。如果这个网络中每条边的容量限制都设为1,那么它的最大流数值就等于二部图的匹配数,而且这个最大流和二部图中的最大匹配是一一对应的。</P>/ A! u# M, I' H5 A+ C
<P align=left>用邻接表存储的二部图可以用匈牙利算法在O(VE) 的时间内找到最大匹配,这意味着用网络流解决二部图最大匹配问题并非最具效率的选择,但是它至少向我们展示了网络流的一个侧面应用。除此之外,网络流的变形和演化还可以解决很多具有普遍意义的问题,比如最小路径覆盖等等,所以笔者建议对图论感兴趣的同学不妨多研究一下相关内容,一定会有所收获。</P></TD></TR></TABLE> |
zan
|