假设以下情景,有一块木板,板上钉上了一些钉子,这些钉子可以由一些细绳连接起来。假设每个钉子可以通过一根或者多根细绳连接起来,那么一定存在这样的情况,即用最少的细绳把所有钉子连接起来。
更为实际的情景是这样的情况,在某地分布着N
个村庄,现在需要在N
个村庄之间修路,每个村庄之前的距离不同,问怎么修最短的路,将各个村庄连接起来。
以上这些问题都可以归纳为最小生成树问题,用正式的表述方法描述为:给定一个无方向的带权图G=(V, E)
,最小生成树为集合T
, T
是以最小代价连接V
中所有顶点所用边E
的最小集合。 集合T
中的边能够形成一颗树,这是因为每个节点(除了根节点)都能向上找到它的一个父节点。
解决最小生成树问题已经有前人开道,Prime
算法和Kruskal
算法,分别从点和边下手解决了该问题。
Prim算法
Prim
算法是一种产生最小生成树的算法。该算法于1930
年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník
)发现;并在1957
年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim
)独立发现;1959
年,艾兹格·迪科斯彻再次发现了该算法。
Prim
算法从任意一个顶点开始,每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim
算法在找当前最近顶点时使用到了贪婪算法。
算法描述:
1. 在一个加权连通图中,顶点集合V
,边集合为E
2. 任意选出一个点作为初始顶点,标记为visit
,计算所有与之相连接的点的距离,选择距离最短的,标记visit
.
3. 重复以下操作,直到所有点都被标记为visit
:
在剩下的点钟,计算与已标记visit
点距离最小的点,标记visit
,证明加入了最小生成树。
下面我们来看一个最小生成树生成的过程:
1 起初,从顶点a
开始生成最小生成树
2 选择顶点a
后,顶点啊置成visit
(涂黑),计算周围与它连接的点的距离:
3 与之相连的点距离分别为7
,6
,4
,选择C
点距离最短,涂黑C
,同时将这条边高亮加入最小生成树:
4 计算与a,c
相连的点的距离(已经涂黑的点不计算),因为与a
相连的已经计算过了,只需要计算与c
相连的点,如果一个点与a,c
都相连,那么它与a
的距离之前已经计算过了,如果它与c的距离更近,则更新距离值,这里计算的是未涂黑的点距离涂黑的点的最近距离,很明显,b
和a
为7
,b
和c
的距离为6
,更新b
和已访问的点集距离为6
,而f
,e
和c
的距离分别是8
,9
,所以还是涂黑b
,高亮边bc
:
5 接下来很明显,d
距离b
最短,将d
涂黑,bd
高亮:
6 f
距离d