题意:有n个结点的有根树,第一个结点为根,n-1条边,第i个数表示这个数和i有一条边,求每个结点遍历的期望值,即同一层的结点的话,会先回溯到根再走到该结点
分析:树形dp,dp[i]表示第i个结点的期望值,假设第i个结点的根dp[root]已知,对于每个孩子dp[x]来说,同一层任意结点在其前面的概率都为1/2,需要先遍历它们,回溯之后再遍历当前子树,得到dp[x] = dp[root] + (size[root] - size[x] - 1) * 0.5 + 1
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
struct edge
{
int to,next;
}e[maxn * 4];
int size[maxn],head[maxn];
double dp[maxn];
int t;
void add(int u,int v)
{
e[t].to = v;
e[t].next = head[u];
head[u] = t++;
}
int getsize(int now,int pre)
{
size[now] = 1;
for(int i = head[now]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(v == pre)continue;
size[now] += getsize(v,now);
}
return size[now];
}
void getres(int now,int pre)
{
for(int i = head[now]; i != -1; i = e[i].next)
{
int v = e[i].to;
if(v == pre)continue;
dp[v] = dp[now] + (size[now] - size[v] - 1) * 0.5 + 1;
getres(v,now);
}
}
int main()
{
int n;
cin>>n;
memset(head,-1,sizeof(head));
for(int i = 2; i <= n; i++)
{
int x;cin>>x;
add(x,i);
add(i,x);
}
getsize(1,1);
dp[1] = 1.0;
getres(1,1);
for(int i = 1; i <= n; i++)
{
if(i == 1)printf("%.7f",dp[i]);
else printf(" %.7f",dp[i]);
}
printf("\n");
return 0;
}