洛谷 1040 加分二叉树
一道难得的DP水题。。。
首先这个中序代表着什么?代表着光明、美好、以及出题人善良的心!
当然,这样同样代表着,题目要求构造的是一棵二叉查找树。(二叉查找树不熟悉的可以看一下我的上一篇博客)。
于是我们可以钦定一个状态f [i] [j] 表示区间 i 到 j 之间点构成的子树的根的编号。
然后限制长度动态规划,我们发现这就变成了一个区间DP的简单题目。
AC代码:
#include <algorithm> #include <iostream> #include <cstdio> #include <cctype> #include <queue> using namespace std; int n; int a[200202]; int f[40][40]; int ans[40][40]; int read() { int x = 0; int k = 1; char c = getchar(); while (!isdigit(c)) if (c == '-') k = -1, c = getchar(); else c = getchar(); while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); return k * x; } void dfs(int root, int l, int r) { if (l > r) return; cout << root << " "; dfs(ans[l][root - 1], l, root - 1); dfs(ans[root + 1][r], root + 1, r); } int main() { n = read(); for (int i = 1; i <= n; ++i) { a[i] = read(); f[i][i] = a[i]; ans[i][i] = i; } for (int l = 2; l <= n; ++l) for (int i = 1, j = l; j <= n; ++i, j = i + l - 1) for (int k = i; k <= j; ++k) { int left = f[i][k - 1]; int right = f[k + 1][j]; if (k == i) left = 1; if (k == j) right = 1; if (f[i][j] < left * right + a[k]) ans[i][j] = k; f[i][j] = max(f[i][j], left * right + a[k]); } cout << f[1][n] << endl; dfs(ans[1][n], 1, n); }