【模板】最小生成树--Kruskal

版权声明:转载请附上地址 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44574520/article/details/87602273