版权声明:转载请附上地址 https://blog.csdn.net/weixin_44574520/article/details/87602273
【模板】最小生成树
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入输出格式
输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz
输入输出样例
输入样例#1: 复制
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例#1: 复制
7
说明
时空限制:1000ms,128M
数据规模:
对于20%的数据:N<=5,M<=20
对于40%的数据:N<=50,M<=2500
对于70%的数据:N<=500,M<=10000
对于100%的数据:N<=5000,M<=200000
Kruskal算法:
转自
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
1. 把图中的所有边按代价从小到大排序;
2. 把图中的n个顶点看成独立的n棵树组成的森林;
3. 按权值从小到大选择边,所选的边连接的两个顶点ui,vi应属于两颗不同的****树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止.
Code:
#include <bits/stdc++.h>
using namespace std;
#define maxm 200010
#define maxn 5010
int n,m,f[maxn],size=0,ans;
struct node{
int u,v,w;
}e[maxm];
inline int 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;
}
inline void clean_(){
size=0;
for(int i=0;i<maxn;i++) f[i]=i;
}
inline bool cmp(node aa,node bb){
return aa.w<bb.w;
}
inline int find_(int x){
if(f[x]==x) return x;
else return f[x]=find_(f[x]);
}
inline void cmerge_(int x,int y){
int rx=find_(x);
int ry=find_(y);
f[rx]=ry;
}
inline void Kruskal_(){
for(int i=1;i<=m;i++){
if(size==(n-1)){
printf("%d",ans);
exit(0);
}
if(find_(e[i].u)!=find_(e[i].v)){
ans+=e[i].w;
cmerge_(e[i].u,e[i].v);
size++;
}
}
if(size<(n-1)) printf("orz");
}
inline void init_(){
freopen("zxscs.txt","r",stdin);
}
inline void readda_(){
clean_();
n=read_();m=read_();
for(int i=1;i<=m;i++){
e[i].u=read_();e[i].v=read_();e[i].w=read_();
}
}
inline void work_(){
sort(e+1,e+m+1,cmp);
Kruskal_();
}
int main(){
init_();
readda_();
work_();
return 0;
}