http://codeforces.com/contest/697/problem/D
给你一个n-1条边的联通图
从1开始 随机的dfs,问 访问到每个节点时,经过的节点数 的期望
很显然是个树dp,我们可以从ans[fa]推得ans[son]
对一个节点u, 影响其期望值的节点有三种,
1是其祖先节点,这些节点必然会在访问u之前被访问,对期望贡献为 1
2是u的子孙节点,这些节点贡献为0
3是既不是祖先又不是子孙的节点,我们看这部分对期望的贡献是多少:
任取 一个x 为第3类节点,y为x的祖先且y为u的兄弟节点(如果存在),那么x在u前面的概率是多少,其实就是相当于y在u的前面的概率。
而容易推地,y与u为兄弟关系,所有兄弟关系的节点之间,谁出现在谁前面的概率都是50%,因此 x在u前面概率也为0.5
即u的贡献为 0.5*1=0.5
所以u的期望计算为 ans[u]=ans[fa]+1 + (所有第三类节点)(num[fa]-num[u]-1)*0.5
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const double pi=acos(-1.0);
double eps=0.000001;
vector<int > mp[123456];
int num[123456],dep[123456];
double ans[123456];
void dfs1(int x)
{
num[x]=1;
if (mp[x].size()==0) return;
for (int i=0;i<mp[x].size();i++)
{
int v=mp[x][i];
dep[v]=dep[x]+1;
dfs1(v);
num[x]+=num[v];
}
}
void dfs2(int x)
{
for (int i=0;i<mp[x].size();i++)
{
int v=mp[x][i];
ans[v]=(num[x]-num[v]-1)*0.5+ans[x]+1;
dfs2(v);
}
}
int main()
{
int n,x;
cin>>n;
for (int i=2;i<=n;i++)
{
scanf("%d",&x);
mp[x].push_back(i);
}
dep[1]=1;
dfs1(1);
ans[1]=1;
dfs2(1);
for (int i=1;i<=n;i++)
{
if (i>1) printf(" ");
printf("%.6lf",ans[i]);
}
printf("\n");
return 0;
}