一道烧脑的黑题,但是代码只有不到10行......
先求出g(n),g(n)代表n个节点的二叉树有多少。
显然g(n)=g(1)*g(n-2)+g(2)*g(n-2)+...+g(n-1)*g(0)
即:左子树有1个节点,右子树就是n-1个节点;左子树有2个节点,右子树就是n-2个节点...以此类推。
最后的g(n-1)*g(0)是一侧子树为空的情况。
这显然是卡特兰数。这里就是卡特兰数的套路:
卡特兰数的两种来源:1.递推式 2.组合数C(2n,n)/(n+1)
在实际应用的过程中,我们经常是通过递推式发现要用到卡特兰数,最后通过组合数的方式把它求出来。
这道题也不例外。
求出了g(n),下面考虑怎么求出g(n)种n个节点的二叉树的叶子节点数的总和f(n)。
可以看出,对于一颗n个节点的二叉树,去掉一个叶子节点,就能够得到一颗n-1个节点的二叉树。
如果这个n个节点的二叉树有k个叶子节点,就能通过这样得到k颗n-1个节点的二叉树。
而把所有的n个节点的二叉树一起考虑,就得到:(所有n个节点的二叉树的叶子节点之和)=(叶子节点数的平均数K)*(n-1个节点的二叉树的总数)。
即:f(n)=K*g(n-1)。
我们还知道,每个n-1个节点的二叉树,都有n个位置可以补上一个叶子。
证明:只有1个节点的树有两个空位置。每增加一个节点,占用原来的一个位置,多出来两个位置。
所以每个n-1个节点的二叉树,都被得到了n次。
最后得到:f(n)=n*g(n-1)。
所以ans=f(n)/g(n)=[n*(n+1)] / [2*(2n-1)]。
1 #include<cstdio> 2 3 int main() 4 { 5 double n; 6 scanf("%lf",&n); 7 printf("%.10lf",n*(n+1)/(4*n-2)); 8 }
Tips:bzoj貌似没有spj,所以在bzoj上提交一定要输出九位小数......