zoukankan      html  css  js  c++  java
  • 跟我一起学算法——最大流

    @

    定义

    最大流(Maximum Flow)

    流网络((flownetwork))

    在有向图 G 中,流是一实函数 f:V×VR,并满足以下三个条件:
    容量限制 :对于所有的 u,v∈V,f(u,v)≤c(u,v)
    反对称性 :对于所有的 u,v∈V,f(u,v)= -f(v,u)
    流守恒 (流进=流出):图中每条边(u,v)∈E 均为非负 容量 c(u,v)≥0。如果(u,v)不
    属于E,则 c(u,v)=0。
    源s,汇t
    某个顶点的 总净流 定义为:净流=流出总正流-流入总正流

    多源多汇

    加入s和t就可变成单源单汇

    剩余网络(residual network)

    剩余网络就是在流网络中除去某个流后, 所有剩余容量(residual capacity)组成的网络。
    剩余流量:二个顶点u,v间的剩余容量定义为:c_f(u,v)=c(u,v)-f(u,v)
    对于给定的流网络G=(V,E)以及流f,则G_f(V,E_f) 是相对与流f的剩余网络。

    增广路径((Augmenting Path)

    从s到t的简单路径p。
    c_f(p) = min(c_f(u,v) ; (u,v) ∈ p) , 即增广路径的最大流量由p中边的最小容量决定。
    令f是流网络G=(V,E)的一个流,令P是剩余网络Gf的一 条增广路径。定义函数f_p:V×V->R,则
    f_p是G_f的一个流且流值为 |f_p|=c_f(P)>0
    定义函数f’:V×V->R且f’=f+fp,那么f’ 是G中的一个流,其流值|f’|=|f|+|f_p|>|f|。

    截(Cut)

    流网络的截(S,T)是顶点V的一种划分,其中T=V-S, s∈S,t∈T。
    流函数f(S,T):穿越截(S,T)的净流,即流出总正流- 流入总正流。
    C(S,T):截(S,T)的容量,即从S到T的容量之和。
    最小截:所有截中容量最小的截。
    任意截(S,T)的净流f(S,T)=|f|。
    流网络G中的任何流值均受限于G中截的容量限制, f(S,T)<=c(S,T)

    最大流最小截定理:如果f是源为s汇为t的流网络G中的一个流,那么以下条件相等:f是G中的最大流<=>
    剩余网络没有增广路径 <=> G中存在截(S,T),使|f|=C(S,T)
    参考https://www.jianshu.com/p/beca253fdc9f

    Ford-Fulkerson算法

    Ford-Fulkerson-Method(G,s,t)
      初始化流f=0
      while 存在增广路径P
        do 沿增广路径P增加流f
        根据增加的流,更新边的容量
      return f
    

    时间复杂度O(fE) , f为增广路径的数量,可大可小。

    Edmonds-Karp算法

    Edmonds-Karp 算法是 Ford-Fulkerson 方法的一种具体实现。它采用 BFS 搜索方法在剩余网络
    中寻找增广路径。具体做法是先对每条边的权值统一赋值为 1,然后找一条从 s 到 t 的最短
    路径。基于此方法,Edmonds-Karp 算法求最大流的时间为 O(VE^2)。

    应用:最大二分图匹配(Maximum Bipartite Matching)

    1. 二分图
      把顶点集V划分为二个不相交的子集合L和R,即 V=L∪R,L∩R=Φ,并且只有L和R之间存在边,L、R
      内部的顶点间没有边,则称这样的图为二分图。

    2. 匹配
      二分图中具有最多边的匹配称为最大二分图匹配

    3. 求二分图的最大匹配问题
      首先需把二分图转换为流网络:

    • 增加一个源s和汇t及s到L中所有顶点的边以及R中所有顶点到t的边
    • 把无向图改为有向图,方向为s->L->R->t
    • 给所有边赋值为单位容量值
    1. 二分图G的一个最大匹配M的目数等于其相关流 网络G’的最大流f的流值。

    2. 算法时间为O(VE)

    Push-relable算法

    定义

    1. 预流
      V中除了s,t外的v不满足流守恒,若v的净流>=0,称为溢出顶点。

    2. 高度
      h(s)=|V| , h(t)=0 ,保持不变
      其他顶点高度初始化为0,h(u) = 0
      对于边(u,v),h(u)<=h(v)+1

    push

    三个条件:

    1. u为溢出顶点
    2. h(u)=h(v)+1
    3. 存在边容量>0,c_f(u,v)>0

    Push操作:
    向下推的流量d=min(e(u), c_f(u,v)),即取u的净流与边容量的较小值,取后者时称为饱和push。
    e(v) += d
    e(u) -= d
    push后 u,v 之间建立一条反向的容量为d的边,也可以直接抵消正向容量。

    relable

    两个条件:

    1. u为溢出顶点
    2. h(u)<=h(v)

    操作:
    h(u) = 1 + min(h(v)) , v与u相连的顶点。

    初始化(init)

    1. 高度初始化
    2. 把s的流以容量为限推到与之相连的各个顶点,e(u)=c(s,u)

    算法

    push_relanble(G)
      init_preflow(G)
      while there exists a vertex that can be pushed or relabled
        do choose push or relable at will
    

    参考

    《算法导论》
    https://www.jianshu.com/p/beca253fdc9f

  • 相关阅读:
    使用Jquery的Ajax调用后台方法
    FileUpload与UpdatePanel
    OnClick与OnClientClick的时序和条件
    LinQ使用积累
    If...Else转换为Action的写法
    淘宝对接(二)
    淘宝对接(一)
    dialog传值
    android sdk开发包国内下载地址合集
    admob android
  • 原文地址:https://www.cnblogs.com/chzhyang/p/12402492.html
Copyright © 2011-2022 走看看