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]转移而来即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }