[原]network flow 网络流

人们经常使用图形去建模网络,源点,目的点,边,负载能力,流这些概念经常使用于网络流。
网络流:
考虑这种形式:每条边可以有一定的负载能力,而有一定的流通过边,所有流产生于唯一的顶点,终止于唯一的目的点。
1每条边都有负载能力,非负整数,Ce
2有一个源点S
3一个目的点T
三条假设:
源点只有出去的边,目的点只有进入边;
每个点都有边;
所有负载能力为整数。
定义流:
s-t流是一个函数f,每条边都有一个映射的值,为非负实数。
f(e)直观上代表边e携带的流量;
f必须满足一下条件:
1对于每条边e,  0<= f(e)<= Ce
2对于所有非源点,非目的点
进入的流量=出去的流量
因此,一条边上的流量不能超过负载能力, 而流对于无源点守恒.
流f的值 v(f) = 从源点出去的流量之和
可以将定义扩展到点集上;
如果几何S包含于点集V,定义fout(S)为所有从S中出去的边的流量的和;
而fin(S) = 所有进入S的流量的和;
通过以上定义,
对于非源点v, fin(V) = fout(v), 而v(f) = fout(s)
最大流问题:
给定一个流网络, 一个很自然的目标就是流量分配,以达到最大效率地使用负载能力.
设计算法:
剩余图:
给定一个流网络, 和其上的流, 定一一个剩余图, Gf.
1Gf的节点集等于G的
2G的每条边e(u, v), 若f(e) < Ce, 就有Ce - f(e)的余量, 我们可以将之发挥出来, 因此在Gf中包含边e(u, v), 能力是Ce - f(e)称该边为前进
3对于每个e(u, v)边f(e) > 0, 都存在f(e)的流量可以收回, 因此我们可以在Gf中包含e'(v, u), 能力是f(e)
在剩余图中,最多有两倍的边
剩余图中的增强路径:
现在开始精确的描述如何在Gf中推进流量.
P是一个简单的Gf中的s-t路径, P中没有任何重复节点.
定义P的流瓶颈 bottleneck(P, f)
作为P中任何边的剩余负载能力.
定义一下操作augment(f, P), 在Gf中产生一个新流f'
augment(f, P)
b = bottleneck(P, f)
for each edge (u, v) belong to p
if e = (u, v) 是一个前进边
增加f(e) += b
else (u, v)是一个后退边
减少f(e) -= b

为了反映增强操作的重要性, 人们通常认为在剩余图中的任何s-t路径, 为增强路径.
算法的结果是Gf的一个新的流量分配, 首先证明这f'是流量:
两个条件:
负载能力限制, 流守恒;
因为f'仅在P的边上与f不同, 检查这些边.
如果(u, v) 是一条前进边, (f中的剩余流量), f'(e) = f(e) + b
 因为Ce-f(e)为前进边当前的能力, 而前进边属于P, 所以瓶颈b <= Ce - f(e);
所以 f'(e) <= Ce;
后退边:
f'(e) = f(e) - b, 因为后退边, 所以 能力为f(e), 且在P上, 所以 b <= f(e)
所以 f'(e) >= 0

在原图中对于中间点,流守恒;
分四种情况: 输入, 前进边, 输出, 后退边. 2*2
新流图中, 若某节点的进入边增加, 因为是中间, 所以必有出去的边, 所以存在出去的边属于P, 所以出去的边减少b;
 同理, 若输入减少b(后退边), 则输出增加b(前进边).

这个增强算法, 增强了前进边, 削弱了后退边, 现在考虑下面算法:
Max-Flow
初始化所有G中的边e 流量f(e) = 0
若在剩余图Gf中存在路径P
则获得一个简单路径P'
f' = augment(f, P')
更新f 为f'
更新剩余图
循环知道没有路径为止

分析算法终止和运行时间
1在每一个算法的中间结果, 流f(e) 和剩余图都是整数;
在while循环的迭代开始时,正确的;
当第j次正确, 因为所有的剩余能力都是整数, 则瓶颈值是整数,因此新的流f‘是整数,因此剩余图的能力是整数.

2f是图G中的流, P是Gf中的简单路径, v(f') = v(f) + bottleneck(f, P)
P中的第一条边, 一定在Gf从s中出来, 因为路径是简单的, 所以不会在遇见s, 因为G没有边进入s, 所以边一定是一个前进边, 在这条边上增加b, 不会改变任何其他的边, 因此v(f') = v(f) + b

3 通过上面, 因为从s输出的能力有限,所以存在流上限, 且每次迭代, 流都严格增加, 且为整数, 所以算法会终止.

接下来考虑算法运行时间:
4假设, 流网络中所有的能力是整数, 算法的实现可以花费O(mC)的时间
证明:
   从3中知道, 算法会终止, 最多迭代C次, 即s的所有输出能力.
  现在考虑, 在每次迭代中所花费的时间:
  剩余图Gf, 拥有最多2m条边(m为G图中的边个数), 因为G中每条边最多被复制两次, 一条前进边, 一条后退边.
  我们通过链表来维护Gf中的边, 和节点关系.
  对每个节点, 都有两个连接链表, 分别为进入的边, 和输入的边.
  为了在Gf中寻找s-t的路径, 可以使用深度优先或者广度优先搜索算法.
  运行时间是O(m+n).
  路径搜索: 从源点的输出开始, 遍历每一条边, 最差情况下, 遍历了每一个节点, 和每一条边, (对于不可达的节点和边要适时减枝);
  在我们的假设中, m >= n/2(因为每个节点都至少连接一条边, 且每条边都有两个顶点)
  因此O(m+n) 近似为O(m)
  所以, 整体的复杂度为O(mC)
 
  最大流和最小分割
  分析算法: 流和割
  以上算法返回的流拥有最大的值;
  考虑, 将图中的点分为两个集合, A, B, s属于A, t属于B. 任何这样的分割都产生一个流最大值的上界(因为所有的流在A, B,之间流动, 不一定A到B, B到A也有可能, 但是考虑A到B的所有负载能力, 确定了一个流的最大上界),
  cut(A, B)的能力称为c(A, B) 为所有从A输出的Ce.
  通过直觉, 分割被认为是一个自然的流值上界.
  1f是任何的s-t流, (A, B)是任意的分割, v(f) = fout(A) - fin(A)
  这个论断比简单的上界要强很多.
  证明:定义v(f) = fout(s), 根据假设, fin(s) = 0;
  因为s没有输入边, 可以写成 v(f) = fout(s) - fin(s)
  对于其他非源, 目的点, fout(v) = fin(v)
  所以 A中的点   fout (v) - fin(v) 的和 = v(f)
  对于边e,, 若端点都在A中, 则+f(e), -f(e) 贡献为0
  对于起始点在A中, 则为+f(e)
  终点在A中 则为-f(e)
  所以fout(A) - fin(A) 为v(f)
  因为A, B是分割, 所以进入B的边就是A中出去的边, 同理有 v(f) = fin(B) - fout(B)
 
  2f是任意的s-t流, (A,B)是任意的s-t分割, v(f) <= c(A, B)

分析算法:
 最大流等于最小分割:
 ...



作者:liyonghelpme 发表于2010/6/20 0:17:00 原文链接
阅读:213 评论:0 查看评论
posted @ 2010-06-20 00:17  liyonghelpme  阅读(157)  评论(0编辑  收藏  举报