CF9d How many trees?

题意:求节点数为n的,高度大于等于h的二叉树的个数。

题解:

  一开始没看到二叉树的限制,,,想了好久。因为数据范围很小,所以可以考虑一些很暴力的做法。

  有2种DP方式都可以过。

  1,f[i][j]表示节点数为i,高度恰好为j的方案数,那么$ans = \sum_{i = h}^{i <= n}{f[n][i]}$.

    于是考虑转移,首先枚举节点数i,然后枚举左儿子Size j,顺便就可以算出右儿子Size,但是因为先枚举节点数为i时的高度不方便转移,所以考虑直接枚举左儿子高度和右儿子高度,然后直接转移即可(具体转移方程看代码)。

    复杂度$n ^ 4$  

  2,f[i][j]表示节点数为i,高度小于等于j的方案数,那么$ans = f[n][n] - f[n][h - 1]$.

    考虑转移,直接枚举左儿子Size,那么就可以算出右儿子Size了,然后因为是高度小于等于j的方案数,所以只需要从f[lson][j - 1] * f[rson][j - 1]转移而来即可。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define R register int
 4 #define AC 40
 5 #define LL long long
 6 
 7 int n, h;
 8 LL ans, f[AC][AC];//i个点,高度恰好为j的方案数
 9 
10 void pre()
11 {
12     scanf("%d%d", &n, &h);
13 }
14 
15 void work()
16 {
17     f[0][0] = 1;
18     for(R i = 1; i <= n; i ++)//枚举点数
19         for(R j = 0; j < i; j ++)//枚举左子树Size
20         {
21             int b = i - j - 1;//右子树大小
22             for(int l = 0; l <= j; l ++)//枚举左子树高度
23                 for(int k = 0; k <= b; k ++)//枚举右子树高度
24                     f[i][max(l, k) + 1] += f[j][l] * f[b][k];
25         }
26     for(R i = h; i <= n; i ++) ans += f[n][i];
27     cout << ans << endl;
28 }
29 
30 void work2()//f[i][j]表示节点数为i,高度小于等于j的方案数
31 {
32     for(R i = 0; i <= n; i ++) f[0][i] = 1;
33     for(R i = 1; i <= n; i ++)//枚举高度
34         for(R j = 1; j <= n; j ++)//枚举节点个数
35             for(R k = 0; k < j; k ++)//枚举左子树size
36                 f[j][i] += f[k][i - 1] * f[j - k - 1][i - 1];
37     cout << f[n][n] - f[n][h - 1] << endl;
38 }
39 
40 int main()
41 {
42     //freopen("in.in", "r", stdin);
43     pre();
44     work2();
45     //fclose(stdin);
46     return 0;
47 }
View Code

 

   

    

posted @ 2018-10-27 22:52  ww3113306  阅读(261)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。