最小生成树常用算法有Kruskal算法,Prim算法,Sollin算法,这里只介绍最常用的Kruskal算法(由Joseph Kruskal在1956年发表)。
Kruskal算法所使用的贪心规则是:从剩下的边中选择一条不会产生环路的具有最小耗费的边加入已选择的边的集合中。注意到所选取的边若产生环路则不可能形成一棵生成树。
图例:
初始图 初始时没有任何边被选择 边(1, 6)是最先选入的边 下一步选择边(3, 4)
下一步选择边(2, 7) 下一步选择边(2, 3) 在其余还未考虑的边中,(7, 4)具有最小耗费,但将它加入正在创建
的树中会产生环路,所以将其丢弃。此后将边(5, 4)加入树中
数据结构的选择:
1) 连通性:用顶点集合来描述每个子图,使用并查集。
2)按耗费非递减的顺序选择边:小根堆。
1 struct DofE {
2 int From, To, Value;
3 DofE(int _From = 0, int _To = 0, int _Value = 0) {
4 From = _From;
5 To = _To;
6 Value = _Value;
7 }
8 bool operator < (const DofE &Elem) const {
9 return Value > Elem.Value;
10 }
11 } Edge[MaxE];
12
13 priority_queue<DofE> Q;
14
15 void Kurskal() {
16 //N:端点数
17 //Uf:并查集
18 //NofE:总边数
19 //Answ:生成树价值
20 int K, A, B;
21 for (int i = 1; i <= NofE; ++i) Q.push(Edge[i]);
22 while(!Q.empty() && K < N) {
23 A = Uf.Find(Q.top().From);
24 B = Uf.Find(Q.top().To);
25 if(A != B) {
26 ++K;
27 Uf.Union(A, B);
28 Answ += Q.top().Value;
29 }
30 Q.pop();
31 }
32 return ;
33 }
复杂度:O(N+ElogE)