CF9D How many trees?(dp-动态规划)

目录

      • 题目描述
      • 输入格式
      • 输出格式
      • 题意翻译
      • 输入输出样例
      • 解题思路

题目描述

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 n n n and h ( n < = 35 , h < = n ) . h ( n<=35 , h<=n ). h(n<=35,h<=n).

输出格式

Output one number — the answer to the problem. It is guaranteed that it does not exceed 9 ⋅ 1 0 18 9·10^{18} 91018

题意翻译

n n n 个点组成二叉树,问高度大于等于 h h h 的有多少个。

输入输出样例

输入 #1

3 2

输出 #1

5

输入 #2

3 3

输出 #2

4

解题思路

  • 这道题其实可以用动态规划来解决。
  • Old Liu said:“正难则反”.这道题直接求答案有些棘手,那么我们不妨反过来想一想。
  • 因为题目求得是高度大于等于 h h h 的二叉树有多少个,那么答案可以由高度为 n n n 的二叉树数量减去高度小于 h h h 的二叉树数量得到。
  • 那么怎么做呢?因为大的二叉树的数量可以由左子树的总数与右子树的总数相乘得到,所以这道题能满足最优子结构和无后效性,因而更能证明这是一道 d p dp dp
  • 首先得设置状态,Old Liu said:“求什么设什么”,我们可以设 d p [ x ] [ y ] dp[x][y] dp[x][y] 表示共有 x x x 个节点,高度为 y y y 的二叉树总数,那么我们可以得到状态转移方程( k k k 表示左子树的节点数量, x − k − 1 x-k-1 xk1 为右子树节点数量):
    d p [ x ] [ y ] = ∑ k = 0 x − 1 d p [ k ] [ y − 1 ] × d p [ x − k − 1 ] [ y − 1 ] dp[x][y]=\sum_{k=0}^{x-1} dp[k][y-1]\times dp[x-k-1][y-1] dp[x][y]=k=0x1dp[k][y1]×dp[xk1][y1]
  • 因为分成左子树和右子树属于分步,所以用 × \times ×,又因为枚举左子树的数量是分类,所以用 + + +
  • 最后还有一点要注意的,就是要预处理,如下:
for (int i=0;i<=n;i++) dp[0][i]=1;
  • 为何?因为空二叉树也算树,貌似没有为什么…
#include 
using namespace std;
typedef long long LL;
LL dp[101][101];
//dp[i][j]为共有i个节点,高度为j的二叉树棵树
void Fre()
{
	freopen("trees.in","r",stdin);
	freopen("trees.out","w",stdout);
}
int main()
{
	Fre();
	int n,h; 
	cin >> n >> h;
	for (int i=0;i<=n;i++) dp[0][i]=1; //预处理(貌似空树也算二叉树)
	for (int i=1;i<=n;i++) //枚举二叉树的高度(最大为n) 
	{
		for (int j=1;j<=n;j++) //枚举二叉树的节点个数 
		{
			for (int k=0;k<j;k++) //枚举左子树的节点个数,从空的情况开始枚举,因为j中包含根节点,所以左子树节点最多为j-1
			{
				dp[j][i]+=/*分类:加法*/dp[k][i-1]* /*分步:乘法*/ dp[j-1-k][i-1];
				//左子树节点数为k,高度为i-1 
				//右子树节点数为j-k-1,高度为i-1 
			} 
		}
	}
	cout << dp[n][n]-dp[n][h-1];
	//n个节点高度为n的情况减去n个节点高度小于h的情况即为答案 
	return 0;
}

你可能感兴趣的:(动态规划/递推,动态规划)