Average distance HDU - 2376(树形dp求树上任意两点距离和的平均值)

Average distance HDU - 2376

Given a tree, calculate the average distance between two vertices in the tree. For example, the average distance between two vertices in the following tree is (d 01 + d 02 + d 03 + d 04 + d 12 +d 13 +d 14 +d 23 +d 24 +d 34)/10 = (6+3+7+9+9+13+15+10+12+2)/10 = 8.6.

这里写图片描述

Input
On the first line an integer t (1 <= t <= 100): the number of test cases. Then for each test case:

One line with an integer n (2 <= n <= 10 000): the number of nodes in the tree. The nodes are numbered from 0 to n - 1.

n - 1 lines, each with three integers a (0 <= a < n), b (0 <= b < n) and d (1 <= d <= 1 000). There is an edge between the nodes with numbers a and b of length d. The resulting graph will be a tree.

Output
For each testcase:

One line with the average distance between two vertices. This value should have either an absolute or a relative error of at most 10 -6

Sample Input

1
5
0 1 6
0 2 3
0 3 7
3 4 2

Sample Output

8.6

题意:

给一棵树,和没两点之间的距离,求任意两点之间距离和的平均值

分析:

我们可以对每条边,求所有可能的路径经过此边的次数:设这条边两端的点的个数分别为 A B ,那 么这条边被经过的次数就是 A × B (即左侧A中选择方案,右侧B中选择方案),它对总的距离和的贡献就是 ( A × B × l e n ) 。我们把所有边的贡献求总和,再除以总路径数 C n 2 = n × ( n 1 ) 2 ,即为最 后所求。

每条边两端的点数的计算,实际上是可以用一次dfs解决的。任取一点为根,在dfs的过程中,对每个点k记录其子树包含的点数(包括其自身),设点数为sum[k],则k的父亲一侧的点数即为N-sum[k]。这个统计可以和遍历同时进行。故时间复杂度为O(n)。

code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 10005;
int sum[maxn],n;
ll dp[maxn];
struct Edge{
    int v,w;
};
vector<Edge> tree[maxn];
void dfs(int cur,int father){
    sum[cur] = 1;//遍历到当前点,只有它本身1个点
    for(int i = 0; i < tree[cur].size(); i++){//遍历它的孩子
        int son = tree[cur][i].v;
        ll len = tree[cur][i].w;
        if(father == son) continue;
        dfs(son,cur);
        sum[cur] += sum[son];//将孩子的节点个数信息返回给父节点(有点类似于线段树向父节点汇总值)
        dp[cur] += dp[son] + (n - sum[son]) * sum[son] * len;
    }
}

int main(){
    int u,v,w,T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i = 0; i < n; i++)
            tree[i].clear();
        memset(sum,0,sizeof(sum));
        memset(dp,0,sizeof(dp));
        for(int i = 0; i < n-1; i++){
            scanf("%d%d%d",&u,&v,&w);
            Edge t1,t2;
            t1.v = v;
            t1.w = w;
            t2.v = u;
            t2.w = w;
            tree[u].push_back(t1);
            tree[v].push_back(t2);
        }
        dfs(0,-1);
        printf("%f\n",dp[0]*2.0/n/(n-1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/82112996