洛谷 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);
}

猜你喜欢

转载自www.cnblogs.com/yanyiming10243247/p/9442570.html