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;
}
posted @ 2025-08-02 16:14  David9006  阅读(12)  评论(0)    收藏  举报