06-3

http://www.patest.cn/contests/mooc-ds/06-3

用并查集找最小生成树

注意

1.路径压缩

//找到x的根节点
int findr(int x){
	//如果该节点为根节点,返回本身
	if(root[x]==-1){
		return x;
	}else{
		int tmp=findr(root[x]);
		//压缩路径
		root[x]=tmp;
		return tmp;
	}

}

2.并查集的合并,是找到2个节点的根节点,然后把根节点合并

int a=findr(a);
int b=findr(b);
if(a!=b){
	root[a]=b;
        ...
 }

并查集过程:

1.记录边的信息

2.将边按照权值排序

3.从排好序的边集一次取出边,判断2个顶点是否合并在一起(在同一棵树上),如果不是,合并

4.最小生成树有n-1条边,且是一棵树(3已经保证是一棵树)


#include <cstdio>
#include <algorithm>
using namespace std;
#define  MAX 3010
struct edge{
	int a;
	int b;
	int cost;
}e[MAX];
int root[MAX];
int findr(int x){
	if(root[x]==-1){
		return x;
	}else{
		int tmp=findr(root[x]);
		root[x]=tmp;
		return tmp;
	}
}
bool cmp(edge m,edge n){
	return m.cost<n.cost;
}
void init(){
	for(int i=0;i<MAX;i++){
		e[i].a=-1;
		e[i].b=-1;
		e[i].cost=-1;
		root[i]=-1;
	}
	
}
int main(){
	freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d %d",&n,&m)!=EOF){
		/*if(n-1>m){
			printf("-1\n");
		}*/
		init();
		for(int i=0;i<m;i++){
			scanf("%d %d %d",&e[i].a,&e[i].b,&e[i].cost);
			int a=e[i].a;
			int b=e[i].b;
			//root[a]=b;
		}
		sort(e,e+m,cmp);
		int cnt=0;
		int cost=0;
		for(int i=0;i<m;i++){
			int a=findr(e[i].a);
			int b=findr(e[i].b);
			if(a!=b){
				root[a]=b;
				cnt++;
				cost+=e[i].cost;
			}
		}
		if(cnt==n-1){
			printf("%d\n",cost);
		}else{
			printf("-1\n");
		}

	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值