|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?我要加入
x
<P><B>一、引言</B></P>
<P align=left>如同我们可以把一个实际的道路地图抽象成一个有向图来计算两点之间的最短路径,我们也可以将一个有向图看作一个流网络来解决另一类型的问题。流网络比较适合用来模拟液体流经管道、电流在电路网络中的运动、信息网络中信息的传递等等类似的过程。</P>
<P align=left><B>二、网络流和最大流问题<BR></B><BR>参看下图,给定一个有向图G=(V,E),把图中的边看作管道,每条边上有一个权值,表示该管道的流量上限。给定源点s和汇点t,现在假设在s处有一个水源,t处有一个蓄水池,问从s到t的最大水流量是多少,类似于这类的问题都可归结为网络流问题。</P>
<P><IMG src="http://www.frontfree.net/articles/pages/0000000554/pic01.gif"></P>
<P align=left>在流网络中,每条有向边可以被看导管。每根导管有一个固定的容量,代表物质流经这个导管的最大速率,例如一个管道每小时最多能流过200加仑液体或者一根电线最多能承载20安培的电流。流网络中的顶点可以看作是导管的连接处。除了源点和汇点之外,物质流进每个点的速率必须等于流出这个点的速率。如果我们把研究的物质特化为电流,这种“流的保持”属性就好像电路中的基尔霍夫电流定律一样。</P>
<P align=left>下面我们用数学语言来进行相关概念的定义:<BR><BR>设G=(V,E)是一个流网络,设c(u, v)>=0 表示从u到v的管道的流量上限。设s为源,t为汇。G的流是一个函数f: V×V →R,且满足下面三个特征:</P>
<P>
<TABLE cellSpacing=1 cellPadding=0 width="100%" bgColor=#000000 border=0>
<TR>
<TD class=tabletxt width="2%" bgColor=#e0e0e0>1. </TD>
<TD class=tabletxt width="98%" bgColor=#ffffff>容量限制:对于所有的 u,v ∈ V, 要求f(u, v) <= c(u, v) </TD></TR>
<TR>
<TD class=tabletxt bgColor=#e0e0e0>2. </TD>
<TD class=tabletxt bgColor=#ffffff>斜对称性:对于所有的 u,v ∈ V, 要求f(u, v) = - f(v, u)</TD></TR>
<TR>
<TD class=tabletxt bgColor=#e0e0e0>3.</TD>
<TD bgColor=#ffffff>
<P>流的保持:对于所有的 u ∈ V - {s, t},要求:∑ f(u, v) = 0(v∈V)<BR>f(u,v)称为从结点u到v的网络流,它可以为正也可以为负。流 f 的值定义为:|f| = ∑ f(s, v)(v∈V)即从源出发的所有流的总和。</P></TD></TR></TABLE></P>
<P align=left>最大流问题就是找出给定流网络的最大流。网络流问题可以归结为一类特殊的线性规划问题。</P>
<P align=left><B>三、解决最大流问题常用算法一览</B></P>
<P align=left>解决最大流问题的常用到Ford-Fulkerson方法,之所以称其方法而不是算法,是因为在这种思想下包含着若干种时间复杂度不同的实现,其中较多地是使用Edmonds-Karp算法。与此相对,Push-relabel算法采用了与Ford-Fulkerson方法完全不同的思考角度,降低了渐进意义下的时间复杂度。而relabel-to-front算法则是对Push-relabel算法的改良和精炼,效率更佳。</P>
<P align=left>关于这三种常用算法的时间复杂度可见下表:(其中V表示图的顶点数,E表示边数)</P>
<P>
<TABLE cellSpacing=1 width="100%" bgColor=#000000 border=0>
<TR bgColor=#e0e0e0>
<TD class=tabletxt width="25%">
<DIV align=center>算法名称</DIV></TD>
<TD class=tabletxt width="23%" bgColor=#ffffff>
<DIV align=center>Edmonds-Karp算法</DIV></TD>
<TD class=tabletxt width="26%" bgColor=#ffffff>
<DIV align=center>一般性的push-relabel算法</DIV></TD>
<TD class=tabletxt width="26%" bgColor=#ffffff>
<DIV align=center>relabel-to-front算法</DIV></TD></TR>
<TR bgColor=#e0e0e0>
<TD class=tabletxt width="25%">
<DIV align=center>时间复杂度</DIV></TD>
<TD class=tabletxt width="23%" bgColor=#ffffff>
<DIV align=center>O(V*E^2)</DIV></TD>
<TD class=tabletxt width="26%" bgColor=#ffffff>
<DIV align=center>O(V^2*E)</DIV></TD>
<TD class=tabletxt width="26%" bgColor=#ffffff>
<DIV align=center>O(V^3)</DIV></TD></TR></TABLE></P>
<P align=left>可以看出,当给定的有向图比较稀疏时,三种算法的效率不会相差太多,但当网络稠密时,relabel-to-front算法在效率上有着明显的优势。<BR><B></B><B>四、基于Ford-Fulkerson方法的Edmonds-Karp实现</B></P>
<P align=left>一般的Ford-Fulkerson方法具有迭代性质,我们把顶点u和v之间的流记作f(u,v)。那么在最开始,我们对所有的u,v∈V置f(u,v)=0。在每次的迭代过程中,通过找到一条增加路径来使|f|增加。在这里,我们可以简单地认为所谓的“增加路径”就是一条可以传送比当前更多流的从源点s到汇点t的路径,一旦找到了这样的路径,我们就可以得到一个比原流数值更大的新流。重复这个过程,直到不存在增加路径为止,这就是Ford-Fulkerson方法的主要过程,可以用伪码表示如下:</P>
<P>
<TABLE cellSpacing=4 cellPadding=0 width="100%" border=0>
<TR>
<TD bgColor=#e0e0e0>
<P align=left>FORD-FULKERSON-METHOD(G,s,t)<BR><BR>将流f初始化为0<BR><BR>while 存在一条增加路径p<BR><BR>do 顺沿p增加f<BR><BR>return f</P></TD></TR></TABLE></P>
<P align=left>实现Ford-Fulkerson的时间复杂度主要取决于如何寻找增加路径p。Edmonds-Karp实现正是通过采用了广度优先的搜索策略得以使其复杂度达到O(V*E^2)。</P>
<P align=left>由于这种算法的效率不很理想,我们在此不多着墨,而主要介绍下述push-relabel算法的思想。</P>
<P align=left><B>五、一般性的push-relabel算法</B></P>
<P align=left>很多渐进意义下最优的算法都是采用了push-relabel算法的思想,而且很多其他的相关问题,比如最小费用流问题,也可以用这种方法很好的解决。首先介绍的是一般性的push-relabel算法。</P>
<P 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>
<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>
<P align=left>正如其名称一样,push-relabel算法有两个基本操作:push和relabel。一般性的push-relabel算法就是通过往复执行这两种操作完成的:</P>
<P>
<TABLE cellSpacing=4 cellPadding=0 width="100%" border=0>
<TR>
<TD bgColor=#e0e0e0>
<P align=left>GENERIC-PUSH-RELABEL(G)<BR><BR>先流初始化<BR><BR>while 存在可以执行的push或relabel操作<BR><BR> 选择一个可以执行的push或relabel操作执行</P></TD></TR></TABLE></P> |
|