Tyvj1073

来源:互联网 发布:mac project软件 编辑:程序博客网 时间:2024/06/16 08:18

题目链接

分析:
我这个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 longusing 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\n",f[1][n]);    print(1,n);    return 0;}