J Z D a y 2 − A JZ\ Day\ 2-A JZ Day 2−A组 − T 2 — — -T2—— −T2——生成输入数据
题目大意:
给你一棵某个完全图唯一的最小生成树。问原来的完全图中所有边可能的最小边权和是多少。
解题思路:
最小生成树怎么搞,就是不断选择两个不同集合的点用集合之间的边权最小的边连接两个集合,我们知道两个集合分别有 X X X个点和 Y Y Y个点,那么我们就有 X ∗ Y X\ *\ Y X ∗ Y种连接方法(完全图),我们知道两个集合之间边权最小的边,那么其他边就是 M A X ( MAX( MAX(本身, 这条边边权 + 1 ) +1) +1)
也就是说,当两个集合之间最小边的边权为 x x x时,其它边 ( u , v ) = m a x ( ( u , v ) , x + 1 ) (u,\ v)\ =\ max((u,\ v),\ x+1) (u, v) = max((u, v), x+1)
Accepted code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 20020;
int T, n, fa[N];
long long ans, size[N];
struct E {
int u, v, w;
} e[N];
int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); }
bool cmp(E x, E y) { return x.w < y.w; }
int main() {
scanf("%d", &T);
while(T --) {
ans = 0;
scanf("%d", &n);
for(int i = 1 ; i < n ; i++) {
scanf("%d %d %d", &e[i].u, &e[i].v, &e[i].w);
fa[i] = i;
size[i] = 1;
}
fa[n] = n;
size[n] = 1;
sort(e+1, e+n, cmp);
for(int i = 1 ; i < n ; i++) {
int u = find(e[i].u), v = find(e[i].v);
if(u != v) {
ans += (size[u] * size[v] - 1) * (e[i].w + 1);
size[u] += size[v];
fa[v] = u;
ans += e[i].w;
}
}
printf("%d", ans); putchar('\n');
}
}