题目链接
自己还是有点害怕树形DP的问题,其是这道题完全是一道区间DP,因为给了中序遍历,所以我们只需要不断的确定在某个区间里选择哪个作为根,然后递归的确定他的左子树选择哪个作为根,右子树选择哪个作为根即可,但是这样自顶向下进行递归肯定会超时,所以我们采取自底向上的区间DP策略:
#define inf 0x3f3f3f3f
#define ll long long
#define vec vector<int>
#define P pair<int,int>
#define MAX 35
int n, a[MAX];
ll dp[MAX][MAX];//dp[i][j]:i-j区间的最大分数
//len:区间长度, [l,r]:左右端点, 目标值
void pre(int l, int r, ll val) {
for (int i = l; i <= r; i++) {
if (dp[l][i - 1] * dp[i + 1][r] + a[i] == val || l == r) {//这是跟
cout << i << " ";
pre(l, i - 1, dp[l][i - 1]);
pre(i + 1, r, dp[i + 1][r]);
return;
}
}
}
int main() {
cin >> n;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
cin >> a[i], dp[i][i] = a[i];
for (int j = 0; j < i; j++)
dp[i][j] = 1;//左端点小于右端点,空树,1
}
for (int i = 2; i <= n; i++) {//枚举区间长度
for (int beg = 1; beg <= n - i + 1; beg++) {//枚举起点
int t = beg + i - 1;
for (int k = beg; k <= t; k++) {//枚举区间内的所有端点
dp[beg][t] = max(dp[beg][t], dp[beg][k - 1] * dp[k + 1][t] + a[k]);
}
}
}
cout << dp[1][n] << endl;
pre(1, n, dp[1][n]);
}