犯了最最低级的错误——竟然把这两种算法弄反了……
浅浅记录一下,两种算法的要点,居然在考试中完完全全的弄反了……
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
Kruskal算法,利用并查集,适合稀疏网(因为稀疏网边少,Kruskal算法需要对边的权值排序,稀疏网边少,排序开销不是很大)
具体思想如下:
先构造一个只含 n 个顶点、而边集为空的子图。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树(使用并查集时就是不属于同一个集合),则将其加入子图。若该条边的两个顶点已落在同一棵树上(并查集的同一个集合),则会造成环路,此条边不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中已经加入 n-1 条边为止。
Prim算法从已知扩散寻找最小。它的实现方式和Dijkstra算法相似但稍微有所区别,Dijkstra是求单源最短路径,而每计算出一个点后,需要以这个点为中转站,更新其他点到源点的距离,而prim不用更新距离。直接找已知点的邻边最小加入即可!
prim和kruskal算法都是从边入手处理。前者是挑选已选顶点集和未选顶点集之间的权值最小的边,后者是挑选全图中权值最小的边。
Prim算法,以图中的某一个顶点为源点开始,适合稠密网(边太多了,kruskal中对边按权值排序,再依次选取进行尝试的开销太大)
具体思想如下:
初始状态顶点集U为空,边集E为空。
(1)寻找图中任意点,以它为源点u,加入顶点集U中。
(2)在剩余顶点中寻找与U中某顶点之间有边且边的权值最小的顶点,将该顶点和这条边分别加入U、E。
重复(2)直到U包含n个顶点。
为啥Prim这里不用判断回路呢?
因为是每次是从剩余顶点中选取顶点加入。新加入的这条已选顶点和剩余顶点之间的边总是不会和已选顶点中存在的边(或者说生成树已构造出的边)构成环路。就好比没进教室之前(未成为生成树的一条边之前),是不可能和教室里的人握手的(形成环路)。
总结就是这样的,纪念一道完全写反的题......