• 最小生成树算法


    以前学运筹学的时候,第一次接触到了贪婪算法,而对于它体现最好的应用貌似就是求最小生成树上了。后来大学时学习算法,看到了贪恋算法在最小生成树上的实现方式,感觉到贪恋的思想真是直观,简洁。但是从那时起到现在对于最小生成树算法的认识也觉得只此一种(后来知道它是Kruskal算法)。

    直到这学期上课,看了Sanjoy Dasgupta, Christos Papadimitriou, Umesh Vazirani三人一起出版的 Algorithms (以下用作者姓的首字母指示该书,即DPV) 之后,才察觉自己的对贪婪算法的认识还处于初级阶段。之后在教授给的作业上,又发现了贪婪算法在求最小生成树上的另一种体现方式。所以在此把他们归总起来。

    这个算法就是最常被提到和使用的算法。

    文字表述(摘自Wikipedia:

    1. 新建图GG中拥有原图中相同的节点,但没有边

    2. 将原图中所有的边按权值从小到大排序

    3. 从权值最小的边开始,如果这条边连接的两个节点于图G中不在同一个连通分量中,则添加这条边到图G中

    4. 重复3,直至图G中所有的节点都在同一个连通分量中

    procedure kruskal(G,w)

    Input: A connected undirected graph G = (V;E) with edge weights we

    Output: A minimum spanning tree defined by the edges X

    for all u ∈ V:

    make set(u)

    X = {}

    Sort the edges E byweight

    //每次选取权重最小的边作为操作对象

    for all edges {u,v}∈ E, in increasing order of weight:

      //如果边的两个端点在不同的集合中,那么我们可以将该边加进来,

      //使集合两个连通组件相互连通

      if find(u) ≠find(v):

      add edge {u,v} toX

      union(u,v)

      //如果两个端点已经在同一个连通图中,那么加进该边就会形成环

      //因此舍弃该边

      if find(u) =find(v): do nothing

     

     

    辅助函数:

    makeset(x):构建一个只包含节点x的集合

    find(x):找出节点所属的集合

    union(x;y): 合并分别包含元素xy的两个集合

     

    通过辅助函数,我们就可以确定各个节点是否已经组合在了一个连通图,当所有的节点都在一个连通图中时,我们就得到了最小生成树。

    DPV一书中,给出了这些辅助函数的一种实现方式,同时还对union函数进行了优化,不过这一部分不是最小生成树算法的主体了,更多的是在研究数据结构方面对算法的贡献。


     


     

    该算法的思想是从已经形成树的部分出发,一步步向外扩张,找到离已形成连通图的部分“最近”的点将其加进来。

     

     

    文字表述(摘自Wikipedia):

    从单一顶点开始,prime算法按照以下步骤逐步扩大树中所含顶点的数目,直到遍及连通图的所有顶点。

    1. 输入:一个加权连通图,其中顶点集合为V,边集合为E;

    2. 初始化:Vnew= {x},其中x为集合V中的任一节点(起始点),Enew= {};

    3. 重复下列操作,直到Vnew= V:

      1. 在集合E中选取权值最小的边(u,v),其中u为集合Vnew中的元素,而v则不是(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

      2. 将v加入集合Vnew中,将(u,v)加入集合Enew中;

    4. 输出:使用集合Vnew和Enew来描述所得到的最小生成树。

    procedure prim(G,w)

    Input: A connected undirected graph G = (V;E) with edge weights we

    Output: A minimum spanning tree defined by the array prev

    for all u ∈ V :

      cost(u)= ∞

      prev(u)= nil

    Pickany initial node u0

      cost(u0)= 0

    H = makequeue(V) (priority queue, using cost-values as keys)

    while H is not empty:

      v = deletemin(H)

      foreach (v; z) ∈ E:

        if cost(z) > w(v; z):

          cost(z)= w(v; z) //<*>

          prev(z)= v

          decreasekey(H;z)

    对比求最短路径的Dijkstra算法,我们会发现他们有极高的相似度

     

    procedure dijkstra(G;l; s)

    Input: Graph G = (V;E), directed or undirected; positive edge lengths {le : e∈E};vertex s ∈ V

    Output:For all vertices u reachable from s, dist(u) is set to the distance from s to u.

    for all u∈V :

      dist(u)= 1

      prev(u)= nil

    dist(s)= 0

    H = makequeue(V) (using dist-values as keys)

    while|H|>0 :

      u = deletemin(H)

      for all edges (u; v) ∈ E:

      if dist(v) > dist(u) + l(u; v):

        dist(v)= dist(u) + l(u; v) //<*>

        prev(v)= u

        decreasekey(H;v)

     

    除了<*>的部分,Prim是直接将边的权重赋上,Dijkstra则是加上前序的累积权重。所以理解和算法记忆上(其实理解了也不用可以去记忆算法的具体实现了,不过对于初学的我还是需要对这些主要的算法做强化记忆),在懂了Dijkstra之后看Prim就不会有很大的难度。

     

    Kruskal和Prim算法其实也还挺常见的,在网上也能搜索到很多相关的内容,但是Borůvka算法提到的就比较少了,在DPV中也没有讲到,我也是在作业中看到它的。

    在我理解下,它相对于Kruskal算法来讲,每次(在while循环中)不止取出一条边进行,及它每次很贪婪很多条边加入到集合中;相对于Prim算法而言,它不止从当前一次连通图向外扩展,而是从多个连通图上同时向外扩展。所以看起来它会执行的很快。

    不过它比其他两种算法有多一点限制,就是每一条边的权重必须各不相同

    procedure boruvka(G,w)

    Input: A connected undirected graph G = (V;E) with edge weights we

    Output: A minimum spanning tree defined by the graph T = {V; E'}

    E'= {}

    while|E'| < |V|-1:

      let C1, ... , Ck be the connected components of T.

      //相对于kruskal算法一次取一条边,该算法每次会取到多条边

      //当然其中自然会有重复的边

      for i = 1 to k:

        ei= min-cost{(v,u) ∈E |v∈Ci&&u ∉ Ci}

      //对于重复的边,根据集合的唯一性将自动舍弃它们

      for i = 1 to k:

        add edge ei to E'

     


     


  • 相关阅读:
    Django的model form
    Django之验证码
    ajax获取跨域数据
    js+css模仿打字效果
    CSS自定义消息提示
    CSS画各种二维图形
    最简单的动态进度条
    利用javascript(自定义事件)记录尺寸可变元素的尺寸变化过程
    超级简单的利用javascript实现文件拖拽事件
    javascript 公历与农历相互转换工具类
  • 原文地址:https://www.cnblogs.com/ider/p/minimum_spanning_tree.html
Copyright © 2020-2023  润新知