CF696B Puzzles(期望dp)

传送门

解题思路

  比较有意思的一道题。首先假如这个点(x)只有(1)个儿子(u),那么显然可得(dp[u]=dp[x]+1)。继续如果多加一个儿子(p),那么(p)(u)前面的概率就是(1/2),也就是说(p)对于(u)的答案有(1/2)的可能产生贡献,而产生的贡献为(siz[p]),那么继续归纳下去,就可以得出转移方程。(dp[u]=dp[x]+1+(siz[x]-siz[u]-1)/2)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;
const int MAXN = 100005;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,head[MAXN],cnt,to[MAXN],nxt[MAXN],siz[MAXN];
double ans[MAXN];

inline void add(int bg,int ed){
    to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}

void dfs1(int x){
    int u;siz[x]=1;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];dfs1(u);
        siz[x]+=siz[u];
    }
}

void dfs2(int x){
    int u;
    for(int i=head[x];i;i=nxt[i]){
        u=to[i];ans[u]=ans[x]+1+(double)(siz[x]-siz[u]-1)/2;
        dfs2(u);
    }
}

int main(){
    n=rd();int x;
    for(int i=2;i<=n;i++)
        x=rd(),add(x,i);
    ans[1]=1.0;dfs1(1);dfs2(1);
    for(int i=1;i<=n;i++) printf("%.8lf ",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/sdfzsyq/p/10050817.html