生成树的概念
在无向连通图中,将图中所有顶点以最少的边连通的子图的操作为生成树。也就是用最少的边保证所有节点的连通性。
生成树的性质
性质一
生成树是一个连通的子图,连接了所有节点且没有环。
性质二
生成树形态不止一种,含有图中n个顶点,以及包含图中n-1条边。
在生成树中,边权和最小的生成树我们称为最小生成树(MST)。
最小生成树写法(kruskal)
1.将边权从小到大排
2.逐个枚举每一条边
若边的左右端点不在一个连通块内,加入该边,把两个连通块合并。
若边的左右端点在一个连通块内,跳过。
3.当加边数达到n-1条,此时得到最小生成树。
例题(kruskal)
题面
洛谷P3366https://www.luogu.com.cn/problem/P3366
代码
#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma Gcc optinize("o1")
#pragma Gcc optinize("o2")
#pragma Gcc optinize("o3")
#pragma GCC optimize("Ofast")
using namespace std;
const int N=2e5+5;
struct node{
int u;
int v;
int w;
}p[N];
int n,m,ans,cnt;
int fa[N];
long long read() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
bool operator <(node x,node y){
return x.w<y.w;
}//重载运算符
int find(int x){
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}//寻找该点的根
void kruskal(){
for(int i=1;i<=n;i++) fa[i]=i;//每个数的根为自己
for(int i=1;i<=m;i++){
int a=find(p[i].u);//寻找a的根
int b=find(p[i].v);//寻找b的根
if(a!=b){//如果这两个点的根不一样,证明这是两棵树的
fa[a]=b;//将两个点变成一个树的
cnt++;//记录选的变的数量
ans+=p[i].w;//记录边权总和
}
if(cnt==n-1) break;//选的边满了就退出
}
if(cnt!=n-1) cout<<"orz";//如果边数不足以形成树,那么输出"orz"
else cout<<ans;//输出边权总和
}
int main(){
n=read();
m=read();
for(int i=1;i<=m;i++){
int x,y,z;
x=read();
y=read();
z=read();
p[i]={x,y,z};
}
sort (p+1,p+m+1);//从小到大排边权
kruskal();
return 0;
}