codeforces 696B puzzle

求随机dfs序的期望。

我们来看到一个点之后是什么情况。

一个点p有很多儿子,其中一个是x;

如果要求x的期望,那么先看:

如果从父亲直接到这个点,那就是父亲的期望加一;

如果还走其他的点,那么最后一步肯定还是要加一(因为你总要花一步从别的店跳过来),所以无论怎样都要父亲的期望加一。剩下来再看,如果跳到别的点,那么就是说明有附加的期望。下面再加上这一部分就行了。

那么现在就是求多出来的这一部分期望。

怎么求呢,首先看清一个问题。

设p0=(son_num[p]-son_num[x])/(all_son-1);

这个是我跳到一个子树的期望(平均子树的期望),由于是期望,所以取了平均。

期望=概率*权值。

下面开始计算:

跳一个其余的子树增加的期望是

(n-1)/n*1/(n-1)*p0;//选一个其余儿子,再选一个x的概率乘一次p0。

跳两个是

(n-1)/n*(n-2)/(n-1)*1/(n-2)*2p0;//选两个其余儿子乘两次p0。

。。。(一共有n-1项)

加起来就是(1+...+n-1)*(son_num[p]-son_num[x])/(n-1)/n;

也就是(son_num[p]-son_num[x])/2.0;

又因为存的时候会带上根节点,所以要再减一;

也就是(son_num[p]-son_num[x]-1)/2.0;

完美~然后上代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <vector>
#include <set>
#include <map>
using namespace std;
int a[100100];
vector<int>edge[100100];
int num_son[100100];
double ans[100100];
int dfs_fir(int root)
{
    num_son[root]=1;
    for (int i=0;i<edge[root].size();i++)
    {
        num_son[root]+=dfs_fir(edge[root][i]);
    }
    return num_son[root];
}
int dfs_sec(int root)
{
    for (int i=0;i<edge[root].size();i++)
    {
        int son=edge[root][i];
        ans[son]=1.0*(num_son[root]-num_son[son]-1)/2.0+ans[root]+1.0;
        dfs_sec(son);
    }
}
int main()
{
    int n;
    scanf ("%d",&n);
    for (int i=2;i<=n;i++)
    {
        scanf ("%d",&a[i]);
        edge[a[i]].push_back(i);
    }
    dfs_fir(1);
    ans[1]=1.0;
    dfs_sec(1);
    for (int i=1;i<n;i++)
        printf ("%.1f ",ans[i]);
    printf ("%.1f\n",ans[n]);
    return 0;
}

 

posted on 2016-07-22 20:07  very_czy  阅读(212)  评论(0编辑  收藏  举报

导航