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;
}