简介
所谓最小生成树,就是一个无向图的极小连通子图,包含原图中的所有节点,且所有边的权值之和最小。因其是一棵树,所以得名最小生成树。
听不懂?那我们来炒一颗栗子:
对于这个无向图:
下图就是它的最小生成树,边权和为$2 + 2 + 3 = 7$:
不过对于一部分图,比如上面炒的栗子,最小生成树有多种解,但是边权和是不变的:
代码
那么概念知道了,代码怎么写呢?
最小生成树有两种算法:Prim和Kruskal。
在稠密图中,Prim比Kruskal优;但在稀疏图中,Kruskal比Prim优。
Prim
Prim的思想是:
从任意一个节点开始,将已连接和未连接的节点各归为一类。
每次找出一个与已连接节点之间边权最小的未连接节点,与其连接。
将上述步骤重复$n - 1$次即可。
Prim每次要选择距离最短的一个节点,并用新的边更新其它节点的距离,这有点像最短路中的Dijkstra算法。
具体一点,就拿上面那个栗子再炒一遍:
我们可以从$1$号点开始:
$1$可以连到$2, 3, 4$,但是$1$和$2, 3$两个点之间的边权是最短的,都是$2$,所以我们可以先连其中一个。边权一样,连哪个都无所谓:
连了$2$之后,边权最短的仍然是$1 - 3$,所以连上$1$和$3$:
现在只剩$4$最后一个点了。由于连接$4$的两条边$1 - 4$和$3 - 4$边权一样,所以连哪条都是正确的,最终结果就会有两个:
1 | // 建图 |
Kruskal
Kruskal算法比较好理解,它的思想是把所有边按边权排序,然后选择边权最小的边,并依次连接。如果存在环(用并查集判断),就跳过这条边,直到加入了$n - 1$条边。
1 | Edge g[MAX_SIZE]; |