题目描述
为了提高智商,ZJY 开始学习概率论。有一天,她想到了这样一个问题:对于一棵随机生成的 �n 个结点的有根二叉树(所有互相不同构的形态等概率出现),它的叶子节点数的期望是多少呢?
判断两棵树是否同构的伪代码如下:
算法 1Check(�1,�2)1Require: 两棵树的节点�1,�22if �1=null or �2=null then 3return �1=null and �2=null4else5return Check(�1→�������,�2→�������) and Check(�1→���ℎ����,�2→���ℎ����)6endif算法 1123456Check(T1,T2)Require: 两棵树的节点T1,T2if T1=null or T2=null then return T1=null and T2=nullelsereturn Check(T1→leftson,T2→leftson) and Check(T1→rightson,T2→rightson)endif
输入格式
输入一个正整数 �n,表示有根树的结点数。
输出格式
输出这棵树期望的叶子节点数,要求误差小于 10−910−9。
输入输出样例
输入 #1
1
输出 #1
1.000000000
输入 #2
3
输出 #2
1.200000000
说明/提示
数据范围
对于 30% 的数据,1≤n≤10。
对于 70% 的数据,1≤n≤1001。
对于 100的数据,1≤n≤109。
解题思路:
首先,我们令��fn表示�n个点的二叉树个数;��gn表示�n个点的所有��fn棵二叉树的叶节点总数。
找规律第一步当然是打表啦~写个爆搜或者手算都可以。
n | 1 | 2 | 3 | 4 | 5 | ... |
---|---|---|---|---|---|---|
��fn | 1 | 2 | 5 | 14 | 42 | ... |
��gn | 1 | 2 | 6 | 20 | 70 | ... |
我们发现一个规律:��=���−1gn=nfn−1。
证明这个规律其实超级简单:
- 对于每棵�n个点的二叉树,如果里面有�k个叶节点,那么我们分别把这�k个叶子删去会得到�k棵�−1n−1个点的二叉树;
- 而每棵�−1n−1个点的二叉树恰好有�n个位置可以悬挂一个新的叶子,所以每棵�−1n−1个点的二叉树被得到了�n次;
- 综上,我们即可得出结论:所有�n个点的二叉树的叶子个数和等于�−1n−1个点的二叉树个数×�×n。
那么我们只需要求出�f即可。而�f的递推式可以通过枚举左子树结点个数得到:
��=∑�=1�−1����−�−1fn=i=1∑n−1fifn−i−1
边界是�1=1f1=1。应该可以一眼看出来这是Catalan数列(其实一看那个1,2,5,14,421,2,5,14,42就应该知道,滑稽)
于是答案即为
����=���−1��fngn=fnnfn−1
代入卡特兰数的通项公式��=(2��)�+1fn=n+1(n2n)很容易就得到上式等于�(�+1)2(2�−1)2(2n−1)n(n+1)。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main(){
double n;
scanf("%lf",&n);
printf("%.9f",n*(n+1)/(2*(2*n-1)));
return 0;
}
拜拜!