加分二叉树 区间dp
题目
思路
由于根节点可以任选, 所以我们可以令\(f[l][r]\) 表示考虑区间\([l, r]\)合并的最优加分二叉树, 那么我们可以从根遍历,则问题转化为区间dp问题
\[f[l][r] = max(f[l][k - 1] \times f[k + 1][r] + w[k]) k \in [l, r], 并且保证对于f数组内的任意值x \ge 1
\]
另外开一个数组记录每一次合并的最优\(k\), 为该中序区间的根,然后进行线序遍历
code
#include <iostream>
#define debug(x) std::cout << x << "\n";
using i64 = long long;
int f[40][40], w[40];
int root[40][40];
void solve(int l, int r) {
if (l > r) return;
// if(root[l][r] == 0) continue;
std::cout << root[l][r] << " ";
if (l >= r) return;
solve(l, root[l][r] - 1);
solve(root[l][r] + 1, r);
}
int main() {
int n;
std::cin >> n;
for (int i = 1; i <= n; i ++) {
std::cin >> w[i];
f[i][i] = w[i];
}
for (int len = 1; len <= n; len ++) {
for (int l = 1; l + len - 1 <= n; l ++) {
int r = l + len - 1;
if (l == r) {
root[l][r] = l;
continue;
}
for (int k = l; k < r; k ++) {
if (f[l][k - 1] * f[k + 1][r] + w[k] > f[l][r]) {
root[l][r] = k;
}
f[l][r] = std::max(f[l][r], std::max(f[l][k - 1], 1) * std::max(f[k + 1][r], 1) + w[k]);
}
}
}
std::cout << f[1][n] << "\n";
solve(1, n);
}