分析:
我这个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;
}