歌名 - 歌手
0:00

    【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]);
    	}
    }
    
    posted @ 2018-05-09 12:38  无尽的蓝黄  阅读(155)  评论(0编辑  收藏  举报