【NOIP2016提高A组模拟7.17】寻找

题目

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的期望值。

分析

发现,当遍历到某个节点是,以该节点为根的子树一定比它的兄弟早遍历。
如果要求x节点,它的兄弟一定会对它有贡献。
对于一个父亲节点F,它的儿子分别是S1、S2、S3······
假设现在求S1,
因为children[v]的顺序随机排列,所以,它的兄弟在它前面的几率是\(\dfrac{1}{2}\)
总贡献
starting_time[S1]=starting_time[F]+(size[S2]+size[S3]+···)/2+1=starting_time[F]+(size[F]-1-size[S1])/2+1

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=100005;
using namespace std;
double f[N];
int size[N],fa[N],next[N*2],last[N*2],to[N*2],n,m,tot;
int bj(int x,int y)
{
    next[++tot]=last[x];
    last[x]=tot;
    to[tot]=y;
}
int dg(int x)
{
    size[x]=1;
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa[x])
        {
            dg(j);
            size[x]+=size[j];
        }
    }
}
int dg1(int x)
{
    for(int i=last[x];i;i=next[i])
    {
        int j=to[i];
        if(j!=fa[x])
        {
            f[j]=f[x]+double(size[x]-1-size[j])*0.5+1;
            dg1(j);
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&fa[i]);
        bj(fa[i],i);
        bj(i,fa[i]);
    }
    dg(1);
    f[1]=1;
    dg1(1);
    for(int i=1;i<=n;i++)
    {
        printf("%.1lf ",f[i]);
    }
}

猜你喜欢

转载自www.cnblogs.com/chen1352/p/9013524.html
今日推荐