1. 程式人生 > >洛谷P3830 [SHOI2012]隨機樹-期望DP

洛谷P3830 [SHOI2012]隨機樹-期望DP

傳送門

題意:

一棵含有n個葉子節點的二叉樹通過如下方式生成:

每次等概率的隨機選擇一個葉子節點,將這個節點加上左右兩個子節點

求:

1.葉子節點平均深度的期望

2.樹深度的期望

n100

Solution:

第一問很好處理:設fx表示有x個葉子節點的樹的葉子節點平均深度

我們考慮在一個有x-1個葉子節點的樹裡隨機選擇一個葉子節點展開,那麼樹的葉子節點深度總和會增加fx1+2

所以fx=fx1(x1)+fx1+2x=fx1+2x

第二問就比較難受了:

首先我們知道一個式子:

E(x)=i=1+P(ix)

說人話就是隨機變數x的期望為對於所有i,ix的概率之和

我們設f[i][j]表示有i個葉子,樹的深度j的概率

轉移時列舉左右子樹有多少個葉子:

f[i][j]=k=1i11i1(f[k][j1]+f[ik][j1]f[k][j1]f[ik][j1])

(括號裡的式子含義:左右只要一邊深度j1即可,所以式子展開其實是

f[k][j1]1+f[ik][j1]1,但這樣會計算兩次兩邊都j1的情況,所以需要減掉)

最後答案即為i=1n1f[n][i]

程式碼:

#include<cstdio>
#include<iostream>
using namespace std;
int p,n;
double f[110],dp[110][110],ans;
int main()
{
    scanf("%d%d",&p,&n);
    if (p==1)
    {
        f[1
]=0; for (int i=2;i<=n;i++) f[i]=f[i-1]+2.0/i; printf("%.6f",f[n]); } else { for (int i=1;i<=n;i++) dp[i][0]=1; for (int i=2;i<=n;i++) for (int j=1;j<i;j++) { for (int k=1;k<i;k++) dp[i][j]+=dp[k][j-1]+dp[i-k][j-1]-dp[k][j-1]*dp[i-k][j-1]; dp[i][j]/=(i-1); } for (int i=1;i<n;i++) ans+=dp[n][i]; printf("%.6f",ans); } }