问题描述
蒜头君最近遇到一道难题,想请聪明的你来帮忙解决一下。题目给了一棵奇怪的二叉树,树上有 n 个结点,每个结点按中序遍历的顺序依次编号为 1 到 n。每个结点都有一个权值,第 i 个结点的权值为 wi。每棵子树也有一个权值,记 s(i) 为以编号 i 为根结点的子树的权值,结点 i 的左孩子结点编号为 ileft,右孩子结点编号为right,则 s(i) 的计算方法为:
s(i)=s(ileft)×s(iright)+wi
需要注意的是,如果结点 i 为叶子结点,则 s(i)=wi。如果结点 i 不是叶子结点,但是其左子树为空,则 s(ileft)=1;同样,如果结点 iii 的右子树为空,则 s(iright)=1。
现在需要你来设计一棵二叉树,使得中序遍历得到的结点序列为 1 到 n,且使二叉树的根结点 root 的 s(root) 最大。
输入格式
输入有两行。
输入第一行是一个整数 n(1≤n≤30),表示二叉树上一共有 n 个结点。
输入第二行是 n 个整数,每两个整数用一个空格隔开,第 i 个整数对应第 i 个结点的权值 wi(1≤wi≤100)。
输出格式
输出两行。
第一行输出一个整数,表示二叉树根结点 root 能获得的最大 s(root),结果保证在 int 范围内。
第二行输出 n 个整数,每两个整数之间用一个空格隔开。输出二叉树的前序遍历结果。
本题答案不唯一,符合要求的答案均正确
样例输入
6
3 5 1 7 9 4
样例输出
297
3 1 2 5 4 6
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n;
int a[50];
int dp[50][50];
int root[50][50];
void pushpath(int l,int r){
if(l>r)return;
cout<<root[l][r]<<" ";
pushpath(l,root[l][r]-1);
pushpath(root[l][r]+1,r);
return;
}
int main(){
cin>>n;
for(int i=0;i<=49;i++){
for(int j=0;j<=49;j++)dp[i][j]=0;
}
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i][i]=a[i];
root[i][i]=i;
}
for (int l=2;l<=n;l++){
int en;
for(int st=1;st<=n-l+1;st++){
en=st+l-1;
for(int k=st+1;k<en;k++){
if(dp[st][k-1]*dp[k+1][en]+a[k]>dp[st][en]){
dp[st][en]=dp[st][k-1]*dp[k+1][en]+a[k];
root[st][en]=k;
}
}
if(dp[st][en-1]+a[en]>dp[st][en]){
dp[st][en]=dp[st][en-1]+a[en];
root[st][en]=en;
}
if(dp[st+1][en]+a[st]>dp[st][en]){
dp[st][en]=dp[st+1][en]+a[st];
root[st][en] = st;
}
}
}
cout<<dp[1][n]<<"\n";
pushpath(1,n);
return 0;
}