题目链接:
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 200010;
int p[N];
struct edge {
int u, v, w;
} edges[N];
//初始化父结点(并查集)
void init() {
for(int i = 0; i < N; i++) p[i] = i;
}
//找根元素(并查集)
int find(int x) {
if(x == p[x]) return x;
return p[x] = find(p[x]);
}
//连接两个点(并查集)
void merge(int x, int y) {
p[find(x)] = find(y);
}
//按边权的大小从小到大排
bool cmp(edge x, edge y) {
return x.w < y.w;
}
int main() {
int t, nume, val;
char s, e;
while(cin >> t) {
int cnt = 0, ans = 0, con = 0;
if(t == 0) break;
//初始化
init();
// t - 1千万别错
for(int i = 0; i < t - 1; i++) {
cin >> s >> nume;
//每次把字符转数字存入边中
for(int j = 0; j < nume; j++) {
cin >> e >> val;
edges[cnt].u = s - 'A' + 1;
edges[cnt].v = e - 'A' + 1;
edges[cnt++].w = val;
}
}
//排序
sort(edges, edges + cnt, cmp);
//以下是kruskal的操作步骤了
for(int i = 0; i < cnt && con != t - 1; i++) {
int a = edges[i].u, b = edges[i].v, c = edges[i].w;
//判断是否以连通
if(find(a) != find(b)) {
merge(a, b);
ans += c;
//连够点数 - 1条边就够了
con++;
}
}
cout << ans << endl;
}
}
这道题是一道经典最小生成树问题了,这里我用了kruskal算法,该算法的主要思路是先存下所有边,然后按边来排序,排完序以后每次选权值最小的那一条边,判断该边两点是否连通。连通则跳过,不连通则连通两个点,同时把其权值加入到ans中。其他的还好,就是要注意读入的时候不要出错。