【JZOJ4647】寻找

Description

Bob和Alice出去度蜜月,但Alice不慎走失,Bob在伤心过后,决定前去寻找Alice。
他们度蜜月的地方是一棵树,共有N个节点,Bob会使用下列DFS算法对该树进行遍历。

starting_time是一个容量为n的数组
current_time = 0
dfs(v):        
       current_time = current_time + 1        
       starting_time[v] = current_time        
       将children[v]的顺序随机排列 (每个排列的概率相同)        
       // children[v]v的直接儿子组成的数组        
       for u in children[v]:               
               dfs(u)

1是这棵树的根,Bob会从1出发,即运行dfs(1),现在他想知道每个点starting_time的期望值。

Solution

看到这题时我一脸懵逼。

于是我盯着样例,于是随便打打就水过去了。

这题我们设 Fi 表示 i 点的期望值,显然,Fsoni= Fi+ 一坨神奇的东西。

首先,我们可以先走一些子树,然后我们把全排列弄出来,(后面与题解相同),发现 j 出现在i前面的概率是 12 ,于是 j i的贡献就为 12sizej (其中 sizej 表示 j 子树的大小)。

于是从根节点往下,Fi=Ffai+sizefaisizei12+1

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
using namespace std;
int sz[N];
int to[N],next[N],last[N],num=0;
void link(int x,int y)
{
    num++;
    to[num]=y;
    next[num]=last[x];
    last[x]=num;
}
double f[N];
void find(int x)
{
    sz[x]=1;
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        find(v);
        sz[x]+=sz[v];
    }
}
void dfs(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        int v=to[i];
        f[v]=f[x]+(sz[x]-sz[v]-1)*0.5+1;
        dfs(v);
    }
}
int main()
{
    int n;
    cin>>n;
    fo(i,2,n)
    {
        int x;
        scanf("%d",&x);
        link(x,i);
    }
    find(1);
    f[1]=1;
    dfs(1);
    fo(i,1,n) printf("%.1lf ",f[i]);
}
posted @ 2016-07-17 16:27  sadstone  阅读(39)  评论(0编辑  收藏  举报