概念
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边
模板题
Kruskal算法
先把边按照权值进行排序,用贪心的思想优先选取权值较小的边,并依次连接,若出现环则跳过此边(用并查集来判断是否存在环)继续搜,直到已经使用的边的数量比总点数少一即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,m;
struct node{
int start,end,v;
};
node edge[2000005];
int parent[5005],rank[5005];
//并查集路径压缩
int find(int x){
if(x==parent[x])return x;
return parent[x]=find(parent[x]);
}
//秩优化
void unio(int x,int y){
int x_root=find(x);
int y_root=find(y);
if(x_root==y_root)return;
if(rank[x_root]>rank[y_root]){
parent[y_root]=x_root;
}else{
parent[x_root]=y_root;
if(rank[x_root]==rank[y_root]){
rank[y_root]++;
}
}
}
bool cmp(node a,node b){
return a.v<b.v;
}
int main(){
scanf("%lld%lld",&n,&m);
//初始化并查集
for(int i=0;i<=n;i++){
parent[i]=i;
rank[i]=0;
}
for(int i=0;i<m;i++){
scanf("%d %d %d",&edge[i].start,&edge[i].end,&edge[i].v);
}
//排序
sort(edge,edge+m,cmp);
long long ans=0,con=0;
//扫描边
for(int i=0;i<m;i++){
//把祖宗都提前求出来减少复杂度
int eu=find(edge[i].start);
int ev=find(edge[i].end);
if(eu!=ev){//不在同一个集合
ans+=edge[i].v;
unio(eu,ev);//加入集合
con++;
if(con==n-1)break;//n个顶点的最小生成树有n-1条边
}
}
if(con<n-1){
cout<<"orz"<<endl;
}else{
printf("%lld\n",ans);
}
return 0;
}