P1040 题解
考虑什么操作会让二叉树的形态变化。我们发现,改变子树的根会让形态变化。
所以,我们枚举根,之后递归计算两个子树的答案,最后合并即可。枚举时记录得到最优答案的那个根,之后按前序遍历(根-左-右)的顺序输出即可。
这可以用记忆化搜索优化获得 100 分。
#include <iostream>
#include <vector>
using namespace std;
using i64 = long long;
vector<int> pt;
vector<vector<unsigned>> dp, root;
unsigned max_pt(int l, int r) // 记忆化搜索
{
if (l > r)
return 1;
else if (l == r) {
root[l][r] = l;
return dp[l][r] = pt[l];
} else if (dp[l][r] != -1U)
return dp[l][r];
unsigned mx_val = 0, mx_pos = -1U;
for (int i = l; i <= r; ++i) {
unsigned val = max_pt(l, i - 1) * max_pt(i + 1, r) + pt[i];
if (mx_val < val) {
mx_val = val;
mx_pos = i;
}
}
root[l][r] = mx_pos;
return dp[l][r] = mx_val;
}
void print_tree(int l, int r) // 输出前序遍历
{
if (l > r)
return;
else if (root[l][r] != -1U)
cout << root[l][r] + 1 << ' ';
print_tree(l, root[l][r] - 1);
print_tree(root[l][r] + 1, r);
}
int main()
{
int n;
cin >> n;
pt.resize(n);
dp.resize(n, vector(n, -1U));
root.resize(n, vector(n, -1U));
for (int& x : pt)
cin >> x;
cout << max_pt(0, n - 1) << '\n';
print_tree(0, n - 1);
return 0;
}

浙公网安备 33010602011771号