- 题意
- 遍历一张图,每个节点的子节点排列方式随机等可能,求每个节点访问到的时间的期望
- 思路
- 假设四个子节点为A,B,C,D,因为排列等可能,所以A在B前面的概率跟A在B后面的概率相等,C和D对于A而言一样。所以遍历A的时间期望就是( t(B) + t(C) + t(D) )/2 + P。其中t(B)是访问B节点及其子树所需时间,尽管是随机排列,但是B子树中的节点树是确定的,所以t(B)可以确定,P是A的父节点访问时间的期望
- 代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100005;
struct Edge{
int u, v, next;
}edge[maxn];
int tot;int first[maxn];
int parent[maxn];
int sub[maxn];
double ans[maxn];
void add(int uu,int vv)
{
edge[tot].u = uu;
edge[tot].v = vv;
edge[tot].next = first[uu];
first[uu] = tot++;
}
void dfs(int u)
{
for(int e = first[u]; e != -1; e = edge[e].next){
dfs(edge[e].v);
sub[u] += sub[edge[e].v];
}
sub[u] += 1;
}
void solve(int u){
for(int e = first[u]; e != -1; e = edge[e].next){
int &v = edge[e].v;
ans[v] = ans[u] + ((double)(sub[u] - sub[v] - 1) / 2) + 1;
solve(v);
}
}
int main()
{
// freopen("data.txt","r",stdin);
memset(first, -1, sizeof(first));
memset(sub, 0, sizeof(sub));
int n;
scanf("%d",&n);
for(int i = 2; i <= n; ++i){
scanf("%d",&parent[i]);
add(parent[i], i);
}
ans[1] = 1;
dfs(1);
// for(int i = 1; i <=n; ++i){
// cout<<sub[i]<<' ';
// }cout <<endl;
solve(1);
printf("%lf",ans[1]);
for(int i = 2; i <=n; ++i){
printf(" %lf", ans[i]);
}
puts("");
return 0;
}
sub记录子树中节点总数