题目链接:点击打开链接
算法步骤:
1)把所有边存在一个数组里边,按权值从小到大排个序
2)从小到大取出每一条边,看看边的两个端点在不在一个联通集上(并查集),如果在就舍弃这条边看下一条,不在就把这两个点并起来,答案加上这条边的长度。
3)判断一下最终是否是联通的,如果是连通的就是一棵最小生成树了。
代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
const int maxn = 10005;
int pre[maxn];
int Find(int x){
int r=x;
while(pre[r]!=r){
r = pre[r];
}
int i=x,j;
while(pre[i]!=r){
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
struct Edge{
int from,to,len;
}edges[maxn];
bool cmp(Edge a, Edge b){
return a.len < b.len;
}
int main(){
int n,m;
while(scanf("%d",&n)){
scanf("%d",&m);
if(n == 0) break;
for(int i=1; i<=m; i++) pre[i] = i;
for(int i=1; i<=n; i++){
scanf("%d%d%d",&edges[i].from,&edges[i].to,&edges[i].len);
}
int ans = 0;
sort(edges+1,edges+n+1,cmp);
for(int i=1; i<=n; i++){
int x = edges[i].from;
int y = edges[i].to;
int fx = Find(x), fy = Find(y);
if(fx!=fy){
pre[fx] = fy;
ans += edges[i].len;
}
}
int cnt = 0;
for(int i=1; i<=m; i++){
if(pre[i] == i) cnt++;
}
if(cnt > 1) printf("?\n");
else printf("%d\n",ans);
}
return 0;
}