您的位置:首页 > 其它

最小生成树总结

2013-05-14 10:01 162 查看
1. 基本原理:

贪心法;通用的算法都是采用这种贪心策略,它在每一个步骤中都形成最小生成树的一条边,算法维护一个变的集合A:保持以下的循环不变式:在每一次循环迭代之前,A是某个最小生成树的一个子集;

2. 基本模式

GENERIC-MST(G,w)
A = Q
while A does not form a spanning tree
find an edge (u,v) that is safe for A
A = AU{(u,v)}
return A


3. 问题的关键:

寻找安全边(使A = AU{(u,v)}仍然是某一个最小生成树子集的边(u,v))。

4. 寻找安全边的规则:

4.1 基本概念

割:无向图G=(V,E)的一个割(S,V-S)是对V的一个划分。

边通过割:当无向图G的一条边一个端点属于S,而另一个端点属于V-S时,称该边通过割(S,V-S)。

割不妨害边集A:如果一个边的集合A中没有边通过该割。

轻边(light edge):如果某条边的权值是通过一个割的所有边中最小的,则称该边位通过这个割的一条轻边。另外还有满足某一性质的轻边。

4.2 添加安全边的定理准则

图G=(V,E)是一个无向图且在边E上定义了加权函数值;A是G的某个最小生成树的子集。设割(S,V-S)是任意一个不妨害边集A的割,且边(u,v)是通过该割的一条轻边。则该边对集合A来说是安全的。

理解:

1)边集A的顶点一定全在S或V-S;

2)包含A的最小生成树可能有多棵;

3)集合A始终是无回路的;

4)在算法执行的任一时刻,图GA=(V,A)是一个森林,GA的每一个连通分支都是一棵树;

5)算法Generic-MST(G,w)每循环一次确定一条最小生成树的边,共执行|V|-1次;初始时,A=∅,GA有|V|棵树,每次迭代过程均减少一颗树,当森林只包含一棵树时,算法终止;

6)该定理可以简述为以下MST性质:假设G=(V,E)是一个连通图网,U是顶点集V的一个非空子集。若(u,v)是一条具有最小权值的边,其中u∈U,v∈V-U,则必存在一棵包含边(u,v)的最小生成树。

5. 分类:

依据通用算法中安全边确定规则细节的不同,分了两种算法:Kruskal和Prim算法

5.1 Kruskal算法

原理:最小生成树子集合A是一个森林,加入集合A中的安全边总是图中连接两个不同联通分支的最小权边;Kruskal算法也是一种贪心算法:算法的每一步中添加到森林中的边的权值都是尽可能小的;

算法:采用了一种不相交集合数据结构,以维护几个互不相交的元素集合:

MST-KRUSKAL(G,W)

//初始化:A为空,并建立|V|棵树,每棵树包含图中一顶点
A = ∅
for each vertex v∈G.V
MAKE-SET(v)

sort the edge(u,v)∈G.E in nondecreasing order by weight w

for edge(u,v)∈G.E, taken in nondecreasing order by weight
if FIND-SET(u) ≠ FIND-SET(v)
A = A∪{(u,v)}


算法时间复杂度:O(ElgE)也可以写成O(ElgV)

5.2 Prim算法

原理:集合A仅形成单棵树,添加入集合A的安全边总是连接该树与一个不在树中的顶点的最小权边。因为每次添加到树中的边都是使树的权尽可能小的边,因此,上述策略也是“贪心的”。

算法:

相关数据结构:基于key域(权值w)的最小优先队列Q(存储不在树中所有的顶点);key[V]:所有与树A某一顶点相连的边的最小权值;π[V]:各顶点的双亲结点;

MST-PRIM(G,w,r)

//初始化
for each u∈G.V
key[u] = ∞
π[u] = NIL
key[r] = 0 //根结点初始化为0,成为第一个被处理的顶点
Q = V[G]

//依次确定添于树A的下一个结点u,即与A相连的不在A的最小权边
while Q ≠ ∅
u = EXTRACT-MIN(Q)//找出与通过割(V-Q,Q)的一条轻边相关联的顶点u∈Q(第一次例外)
for each v∈Adj[u]//u加入A后更新A邻接点的key值
if v∈Q and w(u,v)<key[v]
π[v] = u
key[v] = w(u,v)


说明:

1)算法执行过程中,GENERIC-MST的结合A隐含地满足:A={(v,π[v]):v∈V-{r}-Q};当算法终止时,Q是空的,G的最小生成树A={(v,π[v]):v∈V-{r}};

2)基本原理都知道,实现的关键之一是如何保存已经找到得到最小生成树的子集A,本算法巧妙的利用每个顶点的双亲结点得出A;

3)算法实现的关键之二是利用一个队列记录从A到剩余顶点具有最小代价的边,即割(V(A),V-A)的轻边;

时间复杂度:

算法的初始化部分复杂度为O(V);剩下的while循环执行|V|次,循环体内有两个操作,依次是提取轻边和修改邻接点key值。这样复杂度就取决于优先队列Q是如何实现(数组、二叉队列及Fibonacci队列)及图的数据结构,根据其不同,可分为如下部分:

Minimum edge weight data structure

Time complexity (total)

Searching, adjacency matrix

O(V2)

binary heap, adjacency list

O((V+E)logV) = O(ElogV)

Fibonacci heap, adjacency list

O(E+VlogV)

参考文献:《算法导论》、严蔚敏《数据结构》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: