在线评测链接
题目描述
定义二叉搜索树为满足如下性质的特殊二叉树:
- 若其左子树不为空,则左子树上所有结点的值均小于其根结点的值;
- 若其右子树不为空,则右子树上所有结点的值均大于其根结点的值;
若满足以上条件,则称该二叉树的左右子树分别为二叉查找树。
给定一个整数 n n n,塔子哥想构造一棵二叉查找树,由值为 1 1 1 到 n n n 的结点构成,请你帮塔子哥求出所有能够构造出的不同二叉查找树中,高度不超过 k k k 的数量。(根节点高度为 1 1 1)
输入描述
两个整数 n n n 和 k k k,满足 1 ≤ n , k ≤ 35 1 \le n, k \le 35 1≤n,k≤35。
输出描述
一个整数,表示答案。
5 4
26
思路:动态规划/记忆化搜索
定义 c a c h e [ i ] [ j ] cache[i][j] cache[i][j]有 i i i个节点,并且树的高度不超过 j j j的情况下,可以构造的二叉查找树的数量。
具体可以使用动态规划或者记忆化搜索来实现
初始状态为 c a c h e [ n ] [ k ] cache[n][k] cache[n][k],枚举到当前剩余节点个数为 m m m时,我们可以分别枚举给左子树分配 [ 1 : m ] [1:m] [1:m]个节点,右子树分配 [ m − 1 : 0 ] [m-1:0] [m−1:0]个节点,并将对应的方案累乘,即为当前的方案数,累加当前方案数即为最终答案
为了避免重复计算,需要使用记忆化搜索
dfs(cnt, dep)
函数表示当前有cnt个节点,树的高度为dep时,能构造出的二叉查找树的数量。
如果cnt为0,表示没有节点,那么只能构造出一棵空树,所以返回1。如果dep为0,表示树的高度已经超过了k,那么不能再构造出新的树,所以返回0。
代码
C++
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 40;
//[1, n],高度不超过 k
int cache[N][N];
int dfs(int n, int k)
{
if(cache[n][k] != -1) return cache[n][k];
if(k == 0 && n == 0) return 1;
if(k == 0 && n != 0) return 0;
if(n == 0) return 1;
int res = 0;
for(int i = 1; i <= n; ++ i) {
res += dfs(i - 1, k - 1) * dfs(n - i, k - 1);
}
return cache[n][k] = res;
}
int main()
{
int n, k;
cin >> n >> k;
memset(cache, -1, sizeof cache);
cout << dfs(n, k) << endl;
return 0;
}
python代码
from functools import lru_cache
n, k = map(int, input().split())
@lru_cache(maxsize=None)
def dfs(cnt, dep):
if cnt == 0:
return 1
if dep <= 0:
return 0
ans = 0
for i in range(cnt):
lc = dfs(i, dep - 1)
rc = dfs(cnt - i - 1, dep - 1)
ans += lc * rc
return ans
print(dfs(n, k))
Java代码
import java.util.Scanner;
public class Main {
static final int N = 40;
static int[][] cache = new int[N][N];
static int dfs(int n, int k) {
if (cache[n][k] != -1) return cache[n][k];
if (k == 0 && n == 0) return 1;
if (k == 0 && n != 0) return 0;
if (n == 0) return 1;
int res = 0;
for (int i = 1; i <= n; ++i) {
res += dfs(i - 1, k - 1) * dfs(n - i, k - 1);
}
return cache[n][k] = res;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int k = scanner.nextInt();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cache[i][j] = -1;
}
}
System.out.println(dfs(n, k));
}
}