Tyvj1073

题目链接

分析:
我这个zz,老是不看题
总是因为做过一道题而跳过题目,所以忽视了很多条件

这道题,一开始我认为是随意n个点
求任一符合要求的前序遍历

想了好久都觉得很困难

于是又读了一遍题目
发现题目规定二叉树的中序遍历是1,2,3,4,…,n

如果标算太难请坚定信念
不如回头再看一眼题面 ——–Menci

一道区间dp
已知中序遍历,那么一棵子树的所有节点一定在序列中的一个连续区间内
根节点一定在序列中

我们可以枚举根节点
f[i][j]表示i~j的节点是一棵子树
根节点是k
f[i][j]=max{f[i][k-1]*f[k+1][j]+a[k]}

至于最后的输出,我们只要再用一个g数组记录一下f[i][j]最优情况下的根节点是哪个
最后递归输出就好了

附样例图
这里写图片描述

tip

好好读题
不要手残

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

const int N=35;
ll f[N][N];
ll a[N];
int g[N][N];
int n;

void print(int l,int r)
{
    if (l>r) return;
    if (l==r)
    {
        printf("%d ",l);
        return;
    } 
    printf("%d ",g[l][r]);
    print(l,g[l][r]-1);
    print(g[l][r]+1,r);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    for (int i=1;i<=n;i++) f[i][i]=a[i];
    int i,j,k;
    for (i=n-1;i>=1;i--)
        for (j=i+1;j<=n;j++)
            for (k=i;k<=j;k++)
            {
                if (k==i) 
                    if (f[k+1][j]+a[k]>f[i][j]){
                        f[i][j]=f[k+1][j]+a[k];   //无左儿子
                        g[i][j]=k;   //根节点 
                    }
                if (k==j)
                    if (f[i][k-1]+a[k]>f[i][j]){
                        f[i][j]=f[i][k-1]+a[k];   //无右儿子 
                        g[i][j]=k; 
                    } 
                if (k!=i&&k!=j)
                    if (f[i][k-1]*f[k+1][j]+a[k]>f[i][j]){
                        f[i][j]=f[i][k-1]*f[k+1][j]+a[k];
                        g[i][j]=k;
                    } 
            }
    printf("%lld
",f[1][n]);
    print(1,n);
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673304.html