Kruskal比Prim简单的多,对已知边排序,然后从排序的边中跳出N-1条最短的来就可以了,当然,如果在挑的过程中出现环,就丢掉继续找,就只这么直接。
如何判定有没有环?很简单,用并查集就可以。
比如a-b,b-c,c-a构成了环,那么a-b合并,b-c合并后,如果紧接着最小边是c-a,那么并查集的find(c,a)操作就会告诉你,c,a是同一个环内,跳过,继续。
总结一下:
(1)对已知边排序(如果用数组存顶点,那么直接用qsort()就行了,如果用vector,那么sort()就行了)
(2)从已排序的边中找出一条最小边,如果该边与当前最小生成树形成环,跳过,否则合并端点e.a,e.b,将当前边加入最小生成树内。
(3)循环。
由于挑选的过程是一个O(e)的过程,那么其实Kurskal的时间复杂度主要由其排序时间决定,O(eloge)。这也是Kruskal非常适合稀疏图的原因。
1 struct Edge 2 { 3 int a; 4 int b; 5 int weight; 6 }; 7 8 int edgeCmp(const void* ea, const void* eb) 9 { 10 return reinterpret_cast<const Edge*>(ea)->weight - reinterpret_cast<const Edge*>(eb)->weight; 11 } 12 13 int N, M; 14 int p[100010]; 15 Edge e[1000010]; 16 17 int find(int i) 18 { 19 if (p[i] == i) 20 return i; 21 return p[i] = find(p[i]); 22 } 23 24 void merge(int i, int j) 25 { 26 if (find(i) != find(j)) 27 p[find(i)] = find(j); 28 } 29 30 int kruskal() 31 { 32 int res=0; 33 qsort(e, M, sizeof(Edge), edgeCmp); 34 for (int i = 0; i < M; ++i) 35 { 36 if (find(e[i].a) == find(e[i].b)) 37 continue; 38 res += e[i].weight; 39 merge(e[i].a, e[i].b); 40 } 41 42 return res; 43 } 44 45 int main() 46 { 47 scanf("%d%d", &N, &M); 48 for (int i = 1; i <= N; ++i) p[i] = i; 49 for (int i = 0; i < M; ++i) 50 scanf("%d%d%d", &(e[i].a), &(e[i].b), &(e[i].weight)); 51 52 printf("%d\n", kruskal()); 53 54 return 0; 55 }
时间: 2024-10-31 17:08:07