(最小生成树)洛谷P2126 Mzc家中的男家丁

流过昼夜 提交于 2020-01-27 03:27:11

一、用Kruskal算法求最小生成树

基本算法紫书上写的比较详细了,自己理解的话,核心操作就是两步,第一步排序,第二步按照所排顺序连边,这里的排序方式是按照边权由小到大排,连边方式是选不会使得已有部分成环的边,也就是起点和终点不在一个连通分量的边。

二、代码及注释

这里的并查集部分之间搬了之前自己的并查集有关博客的代码。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
//const int maxn=5005;
const int maxn=400005;
int pa[maxn],r[maxn];
int n,m,p;
int findy(int x){
    return pa[x]==x?x:pa[x]=findy(pa[x]);
}
bool pd(int x,int y){
	return (findy(x)==findy(y));
}
void uni(int x,int y){
	int xx=findy(x);
	int yy=findy(y);
	if(xx!=yy){
		if(r[xx]>r[yy]) swap(xx,yy);
		else if(r[xx]==r[yy]) r[xx]++;
		pa[xx]=yy;
		r[yy]+=r[xx];
	}
}
int sum=0;                                  //表示被连通的数目,数目达到n+1即可 
struct edge{
	int from;
	int to;
	int dist;
	edge(int x,int y,int d):from(x),to(y),dist(d){}
};
vector<edge> a;
bool cmp(edge xx,edge yy){
	return xx.dist<yy.dist;
}
int ans=0;
int main(){
	
	cin>>n>>m;
	int x0,y0,w0;
	for(int i=0;i<=n;i++) pa[i]=i;
	for(int i=0;i<m;i++){
		cin>>x0>>y0>>w0;
		a.push_back(edge(x0,y0,w0));
	}
	sort(a.begin(),a.end(),cmp);
	for(int i=0;i<m;i++){
		int xx=a[i].from;                             //遍历每条边并存储一下边的起点和终点 
		int yy=a[i].to;
	  if(!pd(xx,yy)){
	  	uni(xx,yy);
	  	ans+=a[i].dist;
		}
	}
	cout<<ans;
	
	return 0;
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!