zoukankan      html  css  js  c++  java
  • [原]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 查看评论
  • 相关阅读:
    Azure 媒体服务的 RTMP 支持和实时编码器
    在_Linux_中如何使用_gdb_调试_C_程序
    你刚吃的兰州牛肉面,背后就藏着大数据
    《C++覆辙录》——1.9:使用糟糕的语言
    老司机带你用MaxCompute和表格存储玩转车联网数据
    快速部署rabbitMQ教程
    《第一本Docker书(修订版)》——1.3 能用Docker做什么
    《第一本Docker书(修订版)》——第1章_简介_1.1Docker简介
    【DockerCon2017最新技术解读】Docker最新特性介绍
    【DockerCon2017最新技术解读】如何在阿里云一键部署高可用的Kubernetes集群
  • 原文地址:https://www.cnblogs.com/liyonghelpme/p/4273542.html
Copyright © 2011-2022 走看看