2017年第0届浙江工业大学之江学院程序设计竞赛决赛—M

来源:互联网 发布:男士护肤 知乎 旁氏 编辑:程序博客网 时间:2024/05/29 02:24

Problem M: qwb与二叉树

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 105  Solved: 16
[Submit][Status][Web Board]

Description

某一天,qwb正在上数据结构课。老师在讲台上面讲着二叉树,qwb在下面发着呆。
突然qwb想到一个问题:对于一棵n个无编号节点,m个叶子的有根二叉树,有多少种形态呐?你能告诉他吗?

Input

多组输入,处理到文件结束,大约有104组数据。
每一组输入一行,两个正整数n,m(1≤m≤n≤50),意义如题目所述。

Output

每一行输出一个数,表示相应询问的答案,由于答案可能很大,请将答案对109+7取模后输出。

Sample Input

4 2
10 5

Sample Output

6
252

HINT


样例1的6种形态: 



 


【分析】
比赛的时候一直以为自己模拟错了...我也不知道为什么一直以为自己模拟错了...最后10min的时候发现自己模拟的是对的...都不知道当时发生了什么.....
有一道经典面试题是问有n个节点的二叉树有多少种不同的形态
那么用递归的方式可以考虑出:
当节点只有1个的时候,f(1)=1;
当节点只有2个的时候,f(2)=f(1)*f(0)+f(0)*f(1)
当节点只有3个的时候,f(3)=f(2)*f(0)+f(1)*f(1)+f(0)*f(2)
//以一个点为根,它的左子树和右子树所有节点数的所有可能性
类推可以得到f(n)=f(n-1)f(0)+f(n-2)f(1)+……….+f(1)f(n-2)+f(0)f(n-1) 
//这里这个公式刚好是卡特兰数...

——————
///////////////

如果能理解上面的推导,那这道题无非就是在上面的推导过程中增加一个叶子数
f[i][j]表示节点有i个,叶子有j个的状态数
那么状态转移就直接转移就可以了....f[i][j]可以从上面的每个子树情况中计算所有叶子数加起来为j的状态数...
【代码】
[cpp] view plain copy
  1. #include <stdio.h>  
  2. #define MOD 1000000007  
  3. long long f[60][60]={0};  
  4. int main()  
  5. {  
  6.     f[0][0]=f[1][1]=1;  
  7.     f[2][1]=2;  
  8.     for (int i=3;i<=50;i++)  
  9.         for (int j=1;j<i;j++)  
  10.         {  
  11.             int x=0,y=i-1;  
  12.             for (;x<y;x++,y--)  
  13.             {  
  14.                 for (int k=0;k<=j;k++)  
  15.                     f[i][j]=(f[i][j]+2*((f[x][k]*f[y][j-k])%MOD)%MOD)%MOD;  
  16.             }   
  17.             if (x==y)  
  18.             {  
  19.                 for (int k=0;k<=j;k++)  
  20.                     f[i][j]=(f[i][j]+(f[x][k]*f[y][j-k])%MOD)%MOD;  
  21.             }  
  22.         }  
  23.     int n,m;  
  24.     while (~scanf("%d%d",&n,&m))  
  25.     {  
  26.         printf("%lld\n",f[n][m]);  
  27.     }  
  28.     return 0;  
  29. }  
阅读全文
0 0