CF9D How many trees?
题目描述
In one very old text file there was written Great Wisdom. This Wisdom was so Great that nobody could decipher it, even Phong — the oldest among the inhabitants of Mainframe. But still he managed to get some information from there. For example, he managed to learn that User launches games for pleasure — and then terrible Game Cubes fall down on the city, bringing death to those modules, who cannot win the game...
For sure, as guard Bob appeared in Mainframe many modules stopped fearing Game Cubes. Because Bob (as he is alive yet) has never been defeated by User, and he always meddles with Game Cubes, because he is programmed to this.
However, unpleasant situations can happen, when a Game Cube falls down on Lost Angles. Because there lives a nasty virus — Hexadecimal, who is... mmm... very strange. And she likes to play very much. So, willy-nilly, Bob has to play with her first, and then with User.
This time Hexadecimal invented the following entertainment: Bob has to leap over binary search trees with nn nodes. We should remind you that a binary search tree is a binary tree, each node has a distinct key, for each node the following is true: the left sub-tree of a node contains only nodes with keys less than the node's key, the right sub-tree of a node contains only nodes with keys greater than the node's key. All the keys are different positive integer numbers from 11 to nn . Each node of such a tree can have up to two children, or have no children at all (in the case when a node is a leaf).
In Hexadecimal's game all the trees are different, but the height of each is not lower than hh . In this problem «height» stands for the maximum amount of nodes on the way from the root to the remotest leaf, the root node and the leaf itself included. When Bob leaps over a tree, it disappears. Bob gets the access to a Cube, when there are no trees left. He knows how many trees he will have to leap over in the worst case. And you?
输入格式
The input data contains two space-separated positive integer numbers nn and hh ( n<=35n<=35 , h<=nh<=n ).
输出格式
Output one number — the answer to the problem. It is guaranteed that it does not exceed 9·10^{18}9⋅1018 .
题意翻译
用n个点组成二叉树,问高度大于等于h的有多少个。
输入输出样例
输入 #1复制
输出 #1复制
输入 #2复制
输出 #2复制
题解:
2019.10.31模拟赛T2 爆零场
暴力不会写++。
来说一下我对正解的一些想法:
对于计数题,有两种思路:第一是使用数学知识解决。第二就是考虑递推和DP。我不会告诉你我两个都不会。
因为我不是数学家,所以这道题按照DP的思路来想。
和树有关的DP一半都是从子节点开始考虑。但是显然这道题不是一道树形DP题。所以我们在设计状态的时候需要牢牢抓住这道题的本质:二叉树的高度和节点数的关系。
那么尝试着设置状态:
设(dp[i][j])表示使用(i)个节点能构建的深度大于(j)的二叉树总数。
因为这个东西是二叉树,所以它的状态转移只与左右子树有关。根据乘法原理,最终的答案应该是左子树的答案乘上右子树的答案。
那么我们的转移方程(或者叫做递推式):
来解释一下这个转移方程:
(k)变量枚举的是左子树的节点个数。那么右子树的节点个数就是(i-k-1)(总个数-左子树-根节点),那么这就很好理解了。
在代码实现上,我们需要两重循环来分别枚举深度和节点个数。显然,当这棵树退化成一条链的时候深度最大为(n)。那么就可以得出DP部分的代码。
最后统计答案的时候使用一下差分思想:因为我们的状态设置的是高度大于(j)的树的总数,那么答案就是(dp[n][n]-dp[n][h-1])(最大高度减去合法高度-1)
真的以为这样就结束了么?远远不!
初值...
初值这个地方比较难理解:(dp[0][i]=1)。
啥?0个节点还能构成一棵树?
没办法,就是可以,一棵空树,只有一种可能。
然后就可以开始递推了:代码:
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
int n,h;
int dp[40][40];
//dp[i][j]表示i个节点建立的深度不大于h的二叉树总数。
signed main()
{
scanf("%lld%lld",&n,&h);
for(int i=0;i<=n;i++)
dp[0][i]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<i;k++)
dp[i][j]+=dp[k][j-1]*dp[i-k-1][j-1];
printf("%lld",dp[n][n]-dp[n][h-1]);
return 0;
}