Kruskal算法是求连通网的最小生成树的另一种方法,该算法的思想是从小到大加入边,是个贪心算法,算法的时间主要消耗在对边进行排序,时间复杂度为O(eloge),适合求边数较少图的最小生成树。
算法步骤:
1.记录边的信息,要有边对应的点的编号
2.以边权值进行排序
3.每次从小到大取一条边,如果两个点不是同一个集合,就合并;否则就继续查看下一条边
4.当边数为n - 1时结束遍历,得到最小生成树
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int N = 100010;
typedef struct{
int u;
int v;
int w;
} Edge;
Edge E[N]; //存边
int S[N]; //并查集
int n, e, minSum; //n是点数,e是无向边的边数
//路径压缩
int find(int x){
if(S[x] < 0) return x;
return S[x] = find(S[x]);
}
//按秩归并
void Union(int root1, int root2){
if(S[root1] < S[root2])
S[root2] = root1;
else if(S[root1] == S[root2]){
S[root1]--;
S[root2] = root1;
}
else{
S[root1] = root2;
}
}
//按边权从小到大排序
int cmp(const void *a, const void *b){
return ((Edge*)a)->w - ((Edge*)b)->w;
}
void Kruskal(){
memset(S, -1, sizeof(S));
qsort(E, e, sizeof(Edge), cmp);
int cnt = 0, idx = 0;
while(cnt != n - 1){ //共需要添加n-1条边
int x1 = E[idx].u, x2 = E[idx].v;
int root1 = find(x1);
int root2 = find(x2);
if(root1 != root2){
Union(root1, root2);
minSum += E[idx].w;
cnt++;
}
idx++;
}
}
int main(void){
scanf("%d %d", &n, &e);
int a, b, c;
for(int i = 0; i < e; i++){
scanf("%d %d %d", &a, &b, &c);
E[i].u = a, E[i].v = b, E[i].w = c;
}
Kruskal();
printf("%d\n", minSum);
return 0;
}