【NOIP2003】加分二叉树题解

本博客详细解析了NOIP2003中关于构造加分最高的二叉树的问题。通过分析题面,发现可以采用动态规划的方法解决,特别是树形DP策略。博客介绍了如何定义状态f(i,j)来表示中序遍历i到j位置的最大加分,并给出了状态转移方程。最后,博客提及了寻找问题解决方案的态度对解决问题的重要性。" 88170219,7150420,OSGEarth在MFC中黑屏问题及解决,"['MFC', 'OSGEarth', '图形渲染']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面

题目描述

设一个n 个节点的二叉树T 的中序遍历为(1,2,3,…,n),其中数字 1,2,3,…,n 为节点编号。
每个节点都有一个分数(均为正整数),记第j 个节点的分数为dj。
二叉树T 及它的每个子树都有 一个加分,任意一棵子树S(包括T 本身)的加分等于S 的左子树的加分×S 的右子树的加分+S的根的分数。
若某棵子树为空,规定其加分为1。叶子的加分就是叶节点本身的分数,不考虑它的空子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树T。要求输出T 的最高加分和前序遍历。

输入格式

第1 行:一个整数n(n<30),为节点个数。
地2 行:n个用空格隔开的整数,为每个节点的分数(分数<100)。

输出格式

第1 行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2 行:n个用空格隔开的整数,为该树的前序遍历。

输入样例

5
5 7 1 2 10

输出样例

145
3 1 2 4 5

题解

分析问题

从题目看出在构建加分二叉树的过程中,一个节点的分数最优时,他的子树的分数也一定最优。于是我们想到了动态规划——树形DP。
而我们知道一棵二叉树的中序遍历中,父亲节点的儿子一定在他两旁,所以我们可以想出如下状态:
f(i,j)表示中序遍历中i~j位能达到的分数最大值
目标状态为f(1,n)
状态转移方程:
初始:

f(i,i)=di

转移:
f(i,j)=max{f(i+1,j)+di,f(i,j1)+dj,f(i,k)f(k+1,j)+dk}

至此,题目解决

代码

#include<iostream>
#include<cstring>
using namespace std;

int n;
int best[40][40],root[40][40];
bool first;
void visit(int i,int j)
{
     if (i>j) return;
     if (first) first=false;
     else cout<<" ";
     cout<<root[i][j];
     visit(i,root[i][j]-1);
     visit(root[i][j]+1,j);

} 
int Search_Best(int l,int r)
{
    int i;
    int now;
    if (l>r) return 1;
    else
    {
        if (best[l][r]==-1)
        {
           for (i=l;i<=r;i++)
           {
               now=Search_Best(l,i-1)*Search_Best(i+1,r)+best[i][i];
               if (now>best[l][r])
               {
                  best[l][r]=now;
                  root[l][r]=i;
               }    
           }    
        }    
        return best[l][r];
    }    
}    
int main()
{
    freopen("binary.in","r",stdin);
    freopen("binary.out","w",stdout);
    cin>>n;
    memset(best,-1,sizeof(best));
    memset(root,-1,sizeof(root));
    for (int i=1;i<=n;i++)
    {
        cin>>best[i][i];
        root[i][i]=i;
    }
    cout<<Search_Best(1,n)<<endl;
    first=true;
    visit(1,n);
    cout<<endl<<endl;       
    return 0;
}     

态度决定极限

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值