首页 > 代码库 > Codeforces 437D The Child and Zoo(贪心+并查集)

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

题目链接: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;
}