HDU 2376 Average distance

题目链接:HDU 2376 Average distance

题目大意:
计算一棵树中任意两点之间的距离的平均值。

题解:
如果暴力枚举两点再求距离是显然会超时的。

转换一下思路,我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点数分别为\(a\)\(b\),那么这条边被经过的次数就是\(a\times b\),它对总的距离和的贡献就是\(a\times b \times edge[i].len\),我们把所有边的贡献求总和,再除以总路径数\(\frac{n\times (n-1)}{2}\),即为最后所求。

每条边两端的点数的计算,实际上是可以用一次\(dfs\)解决的。任取一点为根,在\(dfs\)的过程中,对每个点\(k\)记录其子树包含的点数(包括其自身),设点数为\(siz[k]\),则\(k\)的父亲一侧的点数即为\(n-siz[k]\)

#include <cstring>
#include <iomanip>
#include <iostream>
using namespace std;

int siz[10010], n, t, cnt, head[10010];
long long ans;
struct Edge {
    int v, len, next;
} edge[20010];

void addEdge(int u, int v, int w) {
    edge[++cnt].v = v;
    edge[cnt].len = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
}

void dfs(int u, int pre) {
    siz[u] = 1;
    for (int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].v;
        if (v == pre) {
            continue;
        }
        dfs(v, u);
        siz[u] += siz[v];
        ans += 1ll * siz[v] * (n - siz[v]) * edge[i].len;
    }
}

int main() {
    cin >> t;
    while (t--) {
        cnt = 0;
        memset(head, -1, sizeof(head));
        cin >> n;
        for (int i = 1, a, b, d; i < n; ++i) {
            cin >> a >> b >> d;
            addEdge(a, b, d);
            addEdge(b, a, d);
        }
        ans = 0;
        dfs(0, -1);
        cout << fixed << setprecision(6) << (double)ans / (n * (n - 1) / 2) << endl;
    }
    return 0;
}
posted @ 2021-07-26 03:09  ZZHHOOUU  阅读(30)  评论(0编辑  收藏  举报