最小生成树

    一个无向连通图G=(V,E),对于每条边(u,v) ∈E,赋予其权重w(u,v),希望找到一个无环子集T⊆E,既能够将所有的结点连接起来,又具有最小的权重。由于T是无环的,并且连通所有的结点,因此,T必然是一棵树,这样的树为生成树,因为是由图G所生成的,称求取该生成树的问题为最小生成树问题。
    求解最小生成树问题的两种通用算法是Kruskal算法和Prim算法,两种算法都采用贪心算法设计思想。

最小生成树的形成

    假定有一个连通无向图G=(V,E)和权重函数w:E→R,我们希望找出图G中的一棵最小生成树。
    采用贪心思想可以由下面的通用方法来描述。该通用方法在每个时刻生长最小生成树的一条边,并在整个策略的实施过程,管理一个遵守下述循环不变式的边集合A:
    在每遍循环之前,A是某棵最小生成树的一个子集。
    在每一步,我们要做的事情是选择一条边(u,v),将其加入到集合A中,使得A不违反循环不变式,即A∪{(u,v)}也是某棵最小生成树的子集。由于我们可以安全地将这种边加入到集合A而不会破坏A的循环不变式,因此称这样的边为集合A的安全边。

GENERIC_MST(G, w)
A = NULL
while A does not form a spanning tree
  find an edge(u,v) that is safe for A
  A = A∪{(u,v)}
return A

    在寻找安全边之前,先了解一些定义。
    无向图G=(V,E)的一个切割(S,V-S)是集合V的一个划分,如果一条边(u,v) ∈E的一个端点位于集合S,另一个端点位于集合V-S,则称该条边横跨切割(S,V-S)。如果集合A中不存在横跨该切割的边,则称该切割尊重集合A。在横跨一个切割的所有边中,权重最小的边称为轻量级边。一般,如果一条边是满足某个性质的所有边中权重最小的,则称该条边是满足给定性质的一条轻量级边。一个切割的例子如下图所示:
最小生成树_第1张图片
    由上,可得到安全边规则

  • 设G=(V,E)是一个在边E上定义了实数权重函数w的连通无向图。设集合A为E的一个子集,且A包括在图G的某棵最小生成树中,设(S,V-S)是图G中尊重集合A的任意一个切割,又设(u,v)是横跨切割(S,V-S)的一条轻量级边。那么边(u,v)对于集合A是安全的。

    Kruskal算法和Prim算法使用的是上述规则的推论:

  • 设G=(V,E)是一个连通无向图,并有定义在边集合E上的实数权重函数w。设集合A为E的一个子集,且该子集包括在G的某棵最小生成树里,并设C=(Vc,Ec)为森林GA=(V,A)中的一个连通分量(树)。如果边(u,v)是连接C和GA中某个其它连通分量的一条轻量级边,则边(u,v)对于集合A是安全的。

Kruskal算法

    Kruskal算法找到安全边的办法是,在所有连接森林中两棵不同树的边里面,找到权重最小的边(u,v)。设C1和C2为边(u,v)所连接的两棵树。由于边(u,v)一定是连接C1和其他某棵树的一条轻量级边,边(u,v)是C1的一条安全边。
    操作FIND_SET(u)用来返回包含元素u的集合的代表元素,可以通过测试FIND_SET(u)是否等于FIND_SET(v)来判断结点来判断结点u和节点v是否属于同一棵树。Kruskal算法使用UNION过程来对两棵树进行合并。

MST_KRUSKAL(G, w)
A = NULL
for each vertex v ∈ G.V
  MAKE_SET(v)
sort the edges of G.E into nondereasing 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

    执行Kruskal算法过程的一个例子如下图所示:
最小生成树_第2张图片

Prim算法

    Prim算法所具有的一个性质是集合A中的边总是构成一棵树,这棵树从一个任意的根结点r开始,一直长大到覆盖V中所有结点时为止。算法每一步在连接集合A和A之外的结点的所有边中,选择一条轻量级边加入到A中。当算法终止时,A中的边形成一棵最小生成树。
    连通图G和最小生成树的根结点r将作为算法的输入。所有不再树A中的结点存放在一个基于key属性的最小优先队列Q中。对于每个结点v,属性v.key保存的是连接v和树中结点的所有边中最小边的权重。如果不存在这样的边,则v.key=∞。属性v.π给出的是结点v在树中的父结点。

MST_PRIM(G, w, r)
for each u ∈ G.V
  u.key = ∞
  u.π = NULL
r.key = 0
Q = G.V
while Q ≠ NULL
  u = EXTRACT_MIN(Q)
  for each v ∈ G.Adj[u]
    if v ∈ Q and w(u,v) < v.key
      v.π = u
      v.key = w(u,v)

    执行Prim算法过程的一个例子如下图所示:
最小生成树_第3张图片
最小生成树_第4张图片

你可能感兴趣的:(kruskal,prim,最小生成树,算法与数据结构,算法的二三事)