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