ps:B站上的讲解
Kruskal算法的基本思想为:初始时隐去所有的边,这样图中每个顶点都自成一个连通块。之后执行下面的步骤:
- 对所有的边按照从小到大排序。
- 按照边权从小到大测试所有的边,如果当前测试的边所连接的两个顶点不在一个连通块中,则把这条测试边加入当前最小生成树中;否则,将边舍去。
- 执行步骤2,直到最小生成树的边数小于总顶点的数目减一或是测试完所有边结束。当结束时最小生成树的边数小于总顶点数减一,则该图不连通。
模板:
struct node{ //存储边及边权
int u,v,dis;
}e[M];
bool cmp(node x,node y){ //sort的比较函数
return x.dis < y.dis;
}
int father[N]; //存放每个节点的父亲节点的father数组
int findfather(int v){ //查找节点的父亲节点
if(father[v] == v) return v;
else{
int F = findfather(father[v]);
father[v] = F;
return F;
}
}
int Kruskal(int n,int m){
int ans = 0,num_edge = 0;
//ans为所求最小生成树的边权之和,num_edge为当前生成树的边数
for(int i = 0;i< n;i++){ //father[]初始化,注意节点的范围(以0 - n为例)
father[i] = i;
}
sort(e,e+m,cmp); //对边的权值按照从小到大排序
for(int i = 0;i< m;i++){
int fu = findfather(e[i].u);
int fv = findfather(e[i].v);
if(fu != fv){ //如果两个节点的父亲节点不同,则将次边加入最小生成树
ans+= e]i].dis; //加上边权
father[fu] = fv;
num_edge++;
if(num_edge == n-1) //如果最小生成树的边数目达到节点数减一,就退出
break;
}
}
return ans;
}
输入:
6 10
0 1 4
0 4 1
0 5 2
1 2 6
1 5 3
2 3 6
2 5 5
3 4 4
3 5 5
4 5 3
第一行为顶点数和边数
接下来的m行为两个节点以及节点到节点的边权
输出:
15
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,father[100];
struct node{ //边的两个顶点和边权
int u,v,dis;
}e[100];
bool cmp(node x,node y){ //sort函数的比较函数
return x.dis<y.dis;
}
int findf(int v){ //并查集的寻找函数
if(father[v] == v) return v;
else{
int F = findf(father[v]); //注意这里函数的参数是father[v]
father[v] = F;
return F;
}
}
int Kruskal(){
int re = 0,num_edge = 0;
//re为边权之和,num_edge为目前生成树中的边
for(int i = 0;i<n;i++){ //father数组初始化
father[i] = i;
}
sort(e,e+m,cmp); //对边从小到大排序
for(int i = 0;i<m;i++){
int fu = findf(e[i].u); //找到父亲节点
int fv = findf(e[i].v);
if(fv != fu){
re += e[i].dis;
father[fu] = fv;
num_edge++;
if(num_edge == n - 1 ) //如果边的数量达到了生成树的最大边数
break;
}
}
return re;
}
int main(){
freopen("a.txt","r",stdin);
int u,v,k;
cin>>n>>m;
for(int i = 0;i<m;i++){ //读入数据
cin>>u>>v>>k;
e[i].u = u;
e[i].v = v;
e[i].dis = k;
}
cout<<Kruskal()<<endl;
return 0;
}
end.