最小生成树——Kruskal算法、Prim算法

树:连通的、无环的无向图。
特征:n个结点,n-1条无向边,且连通。任意两点之间的路径唯一。填边一条边就会产生环。
生成树:无向连通图的包含所有顶点的极小连通子图。
最小生成树:各边权值总和最小的生成树。

Kruskal算法
1:按照权重从小到大给边排一个序
2:首先创建一个无边的图,并且可以相互到达的结点在同一个集合中(使用并查集来实现),那么初始状态每个结点都是一个单独的集合(因为初始只有结点,还没有放入边)
3:按照之前从小到大排序之后的边,按照从小到大进行遍历,若是当前遍历的边的两端结点没有在同一个集合中,那么这条边就在最小生成树中,并且将边的两端结点的两个集合合并为一个集合;若是在同一个集合中,那么这条边就不再最小生成树中,那么这条边对最后的结果就没贡献。
4:直到遍历到n-1条有效边为止。若是所有的边都遍历完但是没有找到n-1条有向边,那么这个图就不可能组成最小生成树。
注:最小生成树可能并不会唯一,但是最小生成树的总权值一定唯一。
时间复杂度:O(eloge),适用于洗漱图

Prim算法
将图的顶点分为两个部分:处理完的顶点、未处理的顶点
从处理完的顶点中选取一个拓展一个未处理的顶点。对一个只有结点的图加边操作
1:任选一个结点假如到处理完的集合中。初始,处理完的集合中只有一个结点
2:找到两个连接两个集合的最短边,将其加入到图中。并把它的未处理的顶点加入到处理完的集合中。可以给每个顶点记录一个权值,表示和它关联的从处理过的顶点射出的最短边权(初始为无穷大)。
3:之后每一次只需要遍历未处理的顶点,把其中权值最小点的标记为已处理,接着更新和它邻接的顶点就可以了。可以使用优先队列实现。加入的边的两个端点不在同一个集合中。这个可以使用一个数组来标记该结点是否被处理过。
4:直到所有的结点都被标记了。否则那么这个图就不会有最小生成树

复杂度:O(v^2),适用于稠密图。使用优先队列,复杂度为O(vlogv)

 Prim与dijkstra的区别:从算法的描述上和算法的实现上二者都是非常的相似,但是仍然有点细微的区别。这两个算法的核心思想都是将点分为处理过的点的集合U,未处理过的点的集合V.但是Prim每次找的是U-V之间的最短路,而dijkstra找的是源点s到V之间的最短路。所以还是有点细微区别的。

 

写于:2020/8/15 8:01

 

posted @ 2020-08-15 08:02  白菜茄子  阅读(160)  评论(0编辑  收藏  举报