题目传送门:https://www.luogu.com.cn/problem/P3366
题解:利用Kruskal算法求解,这里大致说下Kruskal算法。
对于一个点数为n的生成树而言。很显然,想要成为一个生成树。那么肯定需要n-1条边。不能多也不能少,多了会有环,少了会不连通。
Kruskal算法的做法是:将所有边按照边权值(边的长度等)从小到大排序,每次选择一个边,并且这条边所连接的两个点在还没选择这条边的时候尚未连通,也就是说选了这条边之后不会有环,那么累加这条边的边权值,直到所有边都判断结束。
注意:在判断两个点是否连通,可以用并查集来判断。
代码及注释如下:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 2e5+5;
struct node{
int x,y,z;
friend bool operator < (node a,node b) {
return a.z < b.z;//优先边权小的
}
}a[MAXN];
int dis[MAXN];//记录祖先节点
int getf(int p) {//求祖先,路径压缩
return dis[p]==p?p:dis[p]=getf(dis[p]);
}
int main() {
int n,m;
cin>>n>>m;
for(int i = 1;i <= n;i++) dis[i] = i;//初始化祖先为本身
for(int i = 1;i <= m;i++) {
int x,y,z;
cin>>x>>y>>z;
a[i] = {x,y,z};//存边
}
sort(a+1,a+1+m);//按边权从小到大排序
int ans = 0;
for(int i = 1;i <= m;i++) {//在m个边里面选择
node tmp = a[i];
if(getf(tmp.x)!=getf(tmp.y)) {//若两个点还未连接
ans += tmp.z;//添加边权值
dis[getf(tmp.x)] = dis[getf(tmp.y)];//向左合并
}
}
cout<<ans;
return 0;
}