最小生成树(贪心算法)

最小生成树问题——连接n个针脚,可以使用n-1根连线,每个连线连接两个针脚,使得所使用的连线长度最短     抽象为图问题,一个连通无向图G = (V, E),V是针脚的集合,E是针脚之间的可能连接,且对于每条边都有权重w(u, v),希望找到一个无环子集,T属于E,权重之和最小

通用方法——在每个时刻生长最小生成树的一条边,并在整个策略的实施过程中,管理一个遵守下述循环不变式的边集合A:
    每遍循环之前,A是某棵最小生成树的一个子集     即在每一步,选择一条边(u, v),将其加入到集合A中【贪心算法】,使得A不违反循环不变式;这样的边成为集合A的
安全边 GENERIC-MST(G, w)     A = 空集     while A does not form a spanning tree            //A还不是生成树         find an edge(u, v) that is safe for A         A = A 并上 {(u, v)}     return A

    Kruskal算法和Prim算法在确定安全边的细节有所不同     
在Kruskal算法中,集合A是一个森林,其结点就是给定图中的结点,每次加入到集合A中的安全变永远是权重最小的链接两个不同分量的边;
Prim算法里,集合A是一棵树,每次加入到A中的安全变永远是连接A和A之外某个结点的边中权重最小的边。

Kruskal算法——在所有连接森林中两棵不同树的边里面,找到权重最小的边(u, v)     使用不想交集合结构来维护几棵互不相交的树,即元素集合;FIND-SET(u)能够找到u所在的集合的代表,因此判断两个元素是否在同一个集合,只需要FIND-SET(u) == FIND-SET(v) MST-KRUSKAL(G, w)     A = 空集     for each vertex v 属于 G.V         MAKE-SET(v)     sort the edegs of G.E into nondecreasing order by weight w     for each edge(u, v)属于G.E, taken in nondecreasing order by weight         if FIND-SET(u) != FIND-SET(v)             A = A 并上 {(u, v)}             UNION(u, v)                //将两棵树合并     return A

Prim算法——在连接集合A和A之外的结点的所有边中,选择一条轻量级边加入到A中     所有不在树A中的结点都存放在一个基于key属性的
最小优先队列Q中;对于每个结点v,属性v.key保存的是连接v和树中结点的所有边中最小边的权重(如果不存在则为INF);v.p给出结点v在树中的父结点     从结点r出发构造,集合A维持在A = {(v, v.p) : v 属于 V – {r} – Q};最后生成的最小生成树为A = {(v, v.p) : v 属于 V – {r}} MST-PRIM(G, w, r)     for each u 属于 G.V         u.key = INF         u.p = NIL     r.key = 0     Q = G.V     while Q != 空                                
//即还有结点没包含在生成树中         u = EXTRACT-MIN(Q)              
//提取权重最小的安全边         for each v 属于 G.Adj[u]             if v 属于Q and w(u, v)< v.key        
//还在Q中(即还没选择进来)的需要更新                 v.p = u                 v.key = w(u, v)     
上面的过程少了构造最小优先队列一步,比如初始结点为r,则Q中存储的u.key不应该都为INF,初始化的时候就需要构造最小优先队列;而更新之后也得保持最小优先队列的性质

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/huangwwu11/article/details/45066825
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞