题意:
一棵含有n个叶子节点的二叉树通过如下方式生成:
每次等概率的随机选择一个叶子节点,将这个节点加上左右两个子节点
求:
1.叶子节点平均深度的期望
2.树深度的期望
n≤100 n ≤ 100
Solution:
第一问很好处理:设 fx f x 表示有x个叶子节点的树的叶子节点平均深度
我们考虑在一个有x-1个叶子节点的树里随机选择一个叶子节点展开,那么树的叶子节点深度总和会增加 fx−1+2 f x − 1 + 2
所以 fx=fx−1∗(x−1)+fx−1+2x=fx−1+2x f x = f x − 1 ∗ ( x − 1 ) + f x − 1 + 2 x = f x − 1 + 2 x
第二问就比较难受了:
首先我们知道一个式子:
E(x)=∑+∞i=1P(i≤x) E ( x ) = ∑ i = 1 + ∞ P ( i ≤ x )
说人话就是随机变量x的期望为对于所有i, i≤x i ≤ x 的概率之和
我们设 f[i][j] f [ i ] [ j ] 表示有i个叶子,树的深度 ≥j ≥ j 的概率
转移时枚举左右子树有多少个叶子:
f[i][j]=∑i−1k=11i−1(f[k][j−1]+f[i−k][j−1]−f[k][j−1]∗f[i−k][j−1]) f [ i ] [ j ] = ∑ k = 1 i − 1 1 i − 1 ( f [ k ] [ j − 1 ] + f [ i − k ] [ j − 1 ] − f [ k ] [ j − 1 ] ∗ f [ i − k ] [ j − 1 ] )
(括号里的式子含义:左右只要一边深度 ≥j−1 ≥ j − 1 即可,所以式子展开其实是 f[k][j−1]∗1+f[i−k][j−1]∗1 f [ k ] [ j − 1 ] ∗ 1 + f [ i − k ] [ j − 1 ] ∗ 1 ,但这样会计算两次两边都 ≥j−1 ≥ j − 1 的情况,所以需要减掉)
最后答案即为 ∑n−1i=1f[n][i] ∑ i = 1 n − 1 f [ 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);
}
}