树的高度: 定义为所有叶子到根路径上节点个数的最大值.
例如: 当n=3,m=3时,有如下5种方案:
数据范围:
进阶:时间复杂度
,空间复杂度%5C)
第一行输入两个正整数和
.
输出一个答案表示方案数.
3 3
5
3 2
1
4 3
6
import java.util.*;
public class Main{
public static final int MOD = 1000000007;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
// dp[i][j]表示i个节点最大深度为j的树数量
long[][] dp = new long[n+1][m+1];
Arrays.fill(dp[0], 1);
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
for(int k = 0; k < i; k++) {
// 左子树节点数为k,右子树节点数为i-k-1,且左右子树都要求小于等于j-1
dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1] % MOD) % MOD;
}
}
}
System.out.println(dp[n][m]);
}
}
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;
int main() {
int n; // 节点个数
int m; // 最大高度
cin >> n >> m;
// dp[i][j] 表示 i 个节点能够组成的高度不超过 j 的树的个数
vector<vector<long long>> dp(n + 1, vector<long long>(m + 1));
for(int i = 0; i <= m; ++i) {
dp[0][i] = 1;
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
// 选取一个节点作为根节点
// k 个节点作为左子树,i - k - 1 个节点作为右子树
for(int k = 0; k < i; ++k) {
dp[i][j] = (dp[i][j] + dp[k][j - 1] * dp[i - k - 1][j - 1] % MOD) % MOD;
}
}
}
cout << dp[n][m] << endl;
} #include <bits/stdc++.h>//ASI
typedef long long ll;
using namespace std;
ll n,m,mod=1000000007,f[55][55];
ll dfs(ll n,ll m)
{
if(n<=1)
return 1;
if(f[n][m])
return f[n][m];
ll ans=0,i;
for(i=0; i<n; i++)
{ /**< 易错点,1<<(m-1)当m大于33时会出错。 */
if(i<=(1LL<<(m-1))-1&&n-1-i<=(1LL<<(m-1))-1)
ans=(ans+dfs(i,m-1)*dfs(n-1-i,m-1)%mod)%mod;
}
return f[n][m]=ans;
}
int main()
{
int i,j;
cin>>n>>m;
cout<<dfs(n,m)<<endl;
return 0;
} #include<bits/stdc++.h>
using namespace std;
const int ll = 1000000007;
int main(){
int n, m;
cin >> n >> m;
//dp[i][j]:i个节点且高度不超过j的二叉树个数
vector<vector<long>> dp(n + 1, vector<long>(m + 1, 0));
//初始化dp[0][j] = 1, 即不同高度的空树都只有一种可能
for(int j = 0; j <= m; j++){
dp[0][j] = 1;
}
//其他dp[i][0]都为0
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
//k为左子树节点数,总共有i个节点, 故右子树有i - 1 - k个节点, i ~[0, i - 1]
for(int k = 0; k < i; k++){
//乘法原理,左右子树两两组合,左右子树高度减1
dp[i][j] = (dp[i][j] + dp[k][j - 1] * dp[i - 1 - k][j - 1]) % ll;
}
}
}
cout << dp[n][m] << endl;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
System.out.println(f(a, b));
}
public static int f(int a, int b) {
int mod = 1000000007;
//dp[i][j]表示节点数为i,高度不高于j的树的数量
long [][] dp = new long[a + 1][b + 1];
//首先,节点数为0的树,高度可以任意
for (int i = 0; i <= b; i++) {
dp[0][i] = 1;
}
//其次,除了节点数也为0的,高度为0的树是不存在的
for (int i = 1; i <= a; i++) {
dp[i][0] = 0;
}
for (int i = 1; i <= a; i++) {
for (int j = 1; j <= b; j++) {
//对于含有i个节点,高度不高于j的树,有如下判断
//除去根节点,左右子树加起来共有i-1个节点
for (int k = 0; k <= i - 1; k++) {
if(j>i){
dp[i][j] = dp[i][i];
}else{
//左子树节点数为k,而且高度不高于j-1的
long left = k==0?1:dp[k][j-1];
//右子树节点数为i-1-k,而且高度不高于j-1的
long right = i-1-k==0?1:dp[i-1-k][j-1];
dp[i][j] += left*right%mod;
dp[i][j] %= mod;
}
}
}
}
return (int)dp[a][b];
}
} n, h = list(map(int, input().split())) MAXN = 1e9 + 7 visited = [[0]*55 for i in range(55)] def getNumOfTrees(n, h): if h == 1: return 1 if n < 2 else 0 if n < 2: return 1 if visited[n][h] != 0: return visited[n][h] ret = 0 for i in range(n): l = getNumOfTrees(i, h-1) if i < pow(2, h-1) else 0 r = getNumOfTrees(n-1-i, h-1) if (n-1-i) < pow(2, h-1) else 0 ret += l * r ret %= MAXN visited[n][h] = ret return int(ret % MAXN) print(getNumOfTrees(n, h))
def func(a, b, dp): return 2*dp[a]*dp[b] if a !=b else dp[a]*dp[b] mod = 10 ** 9 + 7 node, layer = list(map(int, input().split())) dp = [0] * (node + 1) dp[0] = 1 for i in range(1, layer+1): bkup = dp[:] for j in range(1, min(2**i, node+1)): a, b = 0, j-1 ans = 0 while a<=b: ans += func(a, b, bkup) a += 1 b -= 1 dp[j] = ans % mod print(dp[-1])
import sys from functools import cache from math import log2 @cache def dfs(n: int, m: int) -> int: if n == 0: return 1 if m < int(log2(n)) + 1: return 0 acc = 0 for k in range(n): acc += dfs(k, m - 1) * dfs(n - 1 - k, m - 1) return acc % e n, m = map(int, input().split()) e = 10 ** 9 + 7 print(dfs(n, m))python,记忆化搜索版本
import java.util.*;
import java.io.*;
public class Main {
private static long[][] dp;
private static int m;
private static long mod = (long)1e9 + 7;
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
while ((s = reader.readLine()) != null) {
String[] s1 = s.split(" ");
int n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
dp = new long[n + 1][m + 1];
for (int i = 0; i <= n; i++) {
Arrays.fill(dp[i], -1);
}
long res = highestNum(n,0);
System.out.println(res);
}
}
//左右节点数量,高度作为状态
public static long highestNum(int treeNum, int high) {
if (high > m) {
return 0l;
}
if (treeNum == 0) {
return 1l;
}
if (dp[treeNum][high] != -1l) {
return dp[treeNum][high];
}
long ans = 0l;
treeNum--;
for (int i = 0; i <= treeNum; i++) {
long left = highestNum(i, high + 1);
long right = highestNum(treeNum - i, high + 1);
ans = (ans +((left % mod) * (right % mod))) % mod;
}
treeNum++;
dp[treeNum][high] = ans;
return ans;
}
} import numpy as np n=int(input()) m=int(input()) MOD=1e9+7 data=np.zeros([n+1,m+1],int) data[0]=[1]*(m+1) for i in range(1,n+1): for j in range(1,m+1): for k in range(i): data[i][j]=(data[i][j]+data[k][j-1]*data[i-k-1][j-1] % MOD)%MOD print(data[i][j])
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1e9 + 7;
//n个节点,高度不超过m一共能组成多少棵BST
long long numofBST(int n, int m){
vector<vector<long long> > dp(n+1, vector<long long>(m+1));
for(int j = 0; j <= m; j++){
dp[0][j] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
for(int k = 0; k < i; k++){ //先用一个点构成root,左子树有k个,右子树有i-k-1个
dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-k-1][j-1] % MOD) % MOD;
}
}
}
return dp[n][m];
}
int main(){
int n, m;
cin >> n >> m;
cout << numofBST(n, m);
return 0;
} #include<bits/stdc++.h>
using namespace std;
static const int mod = 1e9+7;
int main(){
int n,m;
while(cin>>n>>m){
vector<vector<long>> dp(n+1,vector<long>(m+1));
for(int i=0;i<=m;i++) dp[0][i] = 1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<=i-1;k++)
dp[i][j] = (dp[i][j] + dp[i-1-k][j-1]*dp[k][j-1]%mod)%mod;
cout<<dp[n][m]<<endl;
}
} # i->节点数 j->二叉树的高度 # 卡特兰数列,状态转移方程应限制树的高度 # dp[i][j] = dp[i-(i-1)-1][j-1]*dp[(i-1)]dp[j-1] + ... n, m = input().split() n, m = int(n), int(m) dp = [[0]*(m+1) for i in range(n+1)] # 初始状态:结点数为零,只有一种方案 for j in range(m+1): dp[0][j] = 1 for i in range(1, n+1): for j in range(1, m+1): for re in range(i): # re + (i-re-1) = i-1 dp[i][j] += dp[re][j-1]*dp[i-re-1][j-1] print(dp[-1][-1]%(10**9+7))