计蒜客习题:奇怪的二叉树

问题描述

蒜头君最近遇到一道难题,想请聪明的你来帮忙解决一下。题目给了一棵奇怪的二叉树,树上有 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;
}

猜你喜欢

转载自blog.csdn.net/Liukairui/article/details/80984657