您的位置:首页 > 其它

HDU 2376 树形dp|树上任意两点距离和的平均值

2016-07-22 15:15 302 查看
  原题:http://acm.hdu.edu.cn/showproblem.php?pid=2376

  经典问题,求的是树上任意两点和的平均值。

  这里我们不能枚举点,这样n^2的复杂度。我们可以枚举每一条边,设这条边的端点分别为A、B,则通过这条边的路径总数为与A点相连的端点数乘以与B点相连的端点数,再乘以这条边的权值,将所有的和相加,最后除以n*(n-1)/2就可以了(除以2是因为这里每条边重复计算了两次)。

  这里统计求和的时候,一遍深搜就可以了,需要注意的是,假设某个点子树所包含点的个数为k,则这条边另一个端点所包含的点的个数的为n-k。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 11111;
struct node{
int v;//终点
int w;//权值
};
vector<node> tree[maxn];
long long dp[maxn];
int sum[maxn];//统计每个点子树所包含点的个数
int n;
void dfs(int cur,int father){
sum[cur] = 1;
for(int i = 0;i<tree[cur].size();i++){
int son = tree[cur][i].v;
long long len = tree[cur][i].w;
if(father == son)
continue;
dfs(son,cur);
sum[cur] += sum[son];
dp[cur] += dp[son]+sum[son]*(n-sum[son])*len;
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 0;i<n;i++)
tree[i].clear();
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
int u,v,w;
for(int i = 0;i<n-1;i++){
scanf("%d%d%d",&u,&v,&w);
node 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("%lf\n",dp[0]*2.0/n/(n-1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: