第二十三章 最小生成树
总结:这一章介绍了最小生成树,并介绍了找出最小生成树的两个算法,Prim算法和Kruskal算法,它们都用到了贪心策略。
1. 最小生成树
对无向连通图G=(V,E),对图中的每一条边(u,v)єE,都有一个权值w(u,v)。我们希望找出一个无回路的子集T包含于E,它连接了所有的顶点,且其权值之和w(T)=Σw(u,v)为最小。把确定T的问题称为最小生成树问题。
2. Kruskal算法
用了并查集和贪心策略的思路。初始时,所有结点各自为一个集合。先从众多边中,找出权值最小的那条边(u,v),如果这条边属于同一个集合,则说明u,v已经联结在一起了,就不用添加了,否则,就是用最小的代价将两个结点所属的集合合并,这样一直下去即可。
运行时间:O(ElgV)
伪代码
Kruskal(G,w)
A <- 空集
for each vertex vєV[G]
do MAKE-SET(v)
sort the edges of E into nondecreasing order by weight w
for each edge(u,v) є E, taken in nondecreasing order by weight
do if FIND-SET(u)!=FIND-SET(v)
then A <- A U {(u,v)}
UNION(u,v)
return A
3. Prim算法
先选一个点,找出与该点邻接的所有边中最小的那一条,然后将新的结点添加进去,再找与新的集合中那些点相邻接的所有边中最小的那一条,添加进去,这样依次下去,形成一颗最小生成树。
在算法的执行过程中,不在树中的所有顶点都放在一个基于key域的最小优先级队列Q中。对每个顶点v,key[v]是所有将v与树中某一顶点相连的边中的最小权值;若不存在这样的边,则key[v]=无穷大。
运行时间:O(V*EXTRACT-MIN()+E*DECREASE-KEY())
使用二叉最小堆: O(VlgV+ElgV)=O(ElgV)
使用斐波那契堆: O(VlgV+E)
伪代码
MST-PRIM(G,w,r) //r为选择的最初的顶点
for each uєV[G]
do key[u] <- 无穷大
pi[u] <- NIL //pi[u]指在最小生成树中u的父亲结点
key[r] <- 0
Q <- V[G]
while Q!=空
do u <- EXTRACT-MIN(Q)
for each vєAdj[u]
do if vєQ and w(u,v) < key[v]
then pi[v] <- u
key[v] <- w(u,v)