题目大意:
给定一棵树,从1开始,按DFS的方式访问这棵树
每次从父亲节点随机访问儿子,问每个节点被访问到的时间的期望
输入:第一行一个数n,代表n个节点。第二行n-1个数p2,p3,p4,p5...,pn-1,其中pi代表i号节点的父节点编号,1号节点一定是根节点。
Examples
Input
7
1 2 1 1 4 4
Output
1.0 4.0 5.0 3.5 4.5 5.0 5.0
Input
12
1 1 2 2 4 4 3 3 1 10 8
Output
1.0 5.0 5.5 6.5 7.5 8.0 8.0 7.0 7.5 6.5 7.5 8.0
解题报告:
假设当前考虑的是根节点u,对于根节点的子节点,随机产生的一个排列当访问序列,对于某个儿子v,考虑其任意一个兄弟b,该兄弟在其前面的概率均为 1/2。所以这个兄弟对期望的贡献为size(b) ,考虑完所有兄弟,对期望的贡献即为 size[u]-size[v]
所以期望即为 dp[u]+1+size[u]-size[v]。两遍dfs即可。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define FF first
#define SS second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int n,fa[MAX],size[MAX];
double dp[MAX];
vector<int> vv[MAX];
void dfs(int u,int f) {int up = vv[u].size();size[u] = 1;for(int i = 0; i<up; i++) {int v = vv[u][i];if(v == f) continue;dfs(v,u);size[u] += size[v];}}
void dfs2(int u,int f) {int up = vv[u].size();for(int i = 0; i<up; i++) {int v = vv[u][i];if(v == f) continue;dp[v] = dp[u] + 1 + (size[u]-size[v]-1)/2.0;dfs2(v,u);}
}
int main()
{cin>>n;for(int i = 2; i<=n; i++) { scanf("%d",fa+i);vv[fa[i]].pb(i);} dfs(1,0);dp[1]=1;dfs2(1,0);for(int i = 1; i<=n; i++) printf("%.2f ",dp[i]);return 0 ;
}