最小生成树-Kruskal算法

定理:任何一棵最小生成树一定包含无向图中权值最小的边(反证法)

算法思路

Kruskal算法基于上述定理,总是维护无向图的最小生成森林。最初,可认为生成森林由0条边构成,每个节点各自为树。

在任意时刻,从剩余边中选出一条权值最小的,并且两个端点不连通(属于两棵不同的树),把该边加入生成森林。

节点的连通情况用并查集维护。

算法流程

1.建立并查集,每个点各自为一个集合

2.把所有边按权值升序排列,依次扫描每条边(x,y,z)

3.若x,y联通,则忽略这条边,继续扫描下一条

4.否则,合并x,y所在集合,把z累加到答案中

5.所有边完成扫描后,第4步中处理过的边就构成最小生成树

程序O(mlogm)

//by ziwan Catherine
//Kruskal算法 
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct rec{
	int x,y,z;
}edge[500010];
int fa[100010],n,m,ans;
bool operator <(rec a,rec b){
	return a.z<b.z;
}
int get(int x){
	if(x==fa[x]) return x;
	return fa[x]=get(fa[x]);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",edge[i].x,edge[i].y,edge[i].z);
	sort(edge+1,edge+m+1);//把所有边按权值升序排列
	for(int i=1;i<=n;i++) fa[i]=i;//每个点各自为一个集合
	for(int i=1;i<=m;i++){//依次扫描每条边(x,y,z)
		int x=get(edge[i].x);
		int y=get(edge[i].y);
		if(x==y) continue;//若x,y联通,则忽略这条边,继续扫描下一条
		fa[x]=y;
		ans+=edge[i].z;//否则,合并x,y所在集合,把z累加到答案中sa
	}
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zi_wan/article/details/80939498
今日推荐