Codeforces 437D The Child and Zoo(贪心+并查集)

时间:2021-12-08 06:22:39

题目链接:Codeforces 437D The Child and Zoo

题目大意:小孩子去參观动物园,动物园分非常多个区,每一个区有若干种动物,拥有的动物种数作为该区的权值。然后有m条路,每条路的权值为该条路连接的两个区中权值较小的一个。假设两个区没有直接连接,那么f值即为从一个区走到还有一个区中所经过的路中权值最小的值做为权值。问,平均两个区之间移动的权值为多少。

解题思路:并查集+贪心。将全部的边依照权值排序,从最大的開始连接,每次连接时计算的次数为连接两块的节点数的积(乘法原理)。

#include <cstdio>
#include <cstring>
#include <algorithm> using namespace std;
const int N = 1e5+5; struct edge {
int u, v, w;
}e[N]; int n, m, f[N], c[N], w[N]; bool cmp (const edge& a, const edge& b) {
return a.w > b.w;
} int getfar (int x) {
return x == f[x] ? x : f[x] = getfar(f[x]);
} void init () {
scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) {
f[i] = i;
c[i] = 1;
scanf("%d", &w[i]);
} for (int i = 0; i < m; i++) {
scanf("%d%d", &e[i].u, &e[i].v);
e[i].w = min(w[e[i].u], w[e[i].v]);
} sort(e, e + m, cmp);
} int main () {
init();
double ans = 0; for (int i = 0; i < m; i++) {
int p = getfar(e[i].u);
int q = getfar(e[i].v); if (p != q) {
ans += (double)e[i].w * c[p] * c[q];
c[p] += c[q];
f[q] = p;
}
}
printf("%.6lf\n", ans * 2 / (n * 1.0 * (n-1)));
return 0;
}