http://codeforces.com/problemset/problem/9/D
题目大意:给你一个二叉树和n个数字,满足左小右大,能形成多少种不同的二叉树
思路:定义dp[i][j]表示目前有i个节点,根节点为i,深度为j。
然后我们就暴力枚举顶点i,然后以他为树根,再暴力一下左右两个子树就好了。
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 35 + 5; int n, H; LL dp[maxn][maxn]; /* 定义dp[i][j]表示目前结点,深度为j dp[i][j] = sigma(dp[i - k - 1][j - z - 1] * dp[k][z]); */ int main(){ cin >> n >> H; for (int i = 0; i <= n; i++) dp[0][i] = 1; for (int i = 1; i <= n; i++){ for (int h = 1; h <= i; h++){///目前i个组成的最大层数 for (int j = 0; j < i; j++){///left的个数 for (int l = 0; l <= j; l++){///left的最大层数 for (int r = 0; r <= i - j - 1; r++){///右边的最大层数 if (1 + max(l, r) == h){ dp[i][h] += dp[j][l] * dp[i - j - 1][r]; } } } } } } LL ans = 0; for (int i = H; i <= n; i++) ans += dp[n][i]; printf("%lld ", ans); return 0; }
不过我貌似看到了卿学姐写的更加简单,定义的也更加简单
http://www.cnblogs.com/qscqesze/p/5414271.html
定义dp[i][j]表示目前深度小于等于i,有j个节点的所有二叉树的种类数,然后容斥一下就好了
//看看会不会爆int!数组会不会少了一维! //取物问题一定要小心先手胜利的条件 #include <bits/stdc++.h> using namespace std; #define LL long long #define ALL(a) a.begin(), a.end() #define pb push_back #define mk make_pair #define fi first #define se second #define haha printf("haha ") const int maxn = 35 + 5; int n, H; LL dp[maxn][maxn]; /* 定义dp[i][j]表示目前深度小于等于i,有j个节点的所有二叉树的种类数 dp[i][j] = sigma(dp[i - 1][j - k - 1] * dp[i - 1][j - k]); */ int main(){ cin >> n >> H; for (int i = 0; i <= n; i++) {///目前深度为i dp[i][0] = 1; for (int j = 1; j <= n; j++){///总节点数 for (int k = 0; k < j; k++){///左边节点的个数 dp[i][j] += dp[i - 1][k] * dp[i - 1][j - k - 1]; } } } printf("%lld ", dp[n][n] - dp[H - 1][n]); return 0; }