栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

加分二叉树

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

加分二叉树

[NOIP2003 提高组] 加分二叉树 题目描述

设一个 n n n 个节点的二叉树 tree text{tree} tree 的中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,ldots,n) (1,2,3,…,n),其中数字 1 , 2 , 3 , … , n 1,2,3,ldots,n 1,2,3,…,n 为节点编号。每个节点都有一个分数(均为正整数),记第 i i i 个节点的分数为 d i d_i di​, tree text{tree} tree 及它的每个子树都有一个加分,任一棵子树 subtree text{subtree} subtree(也包含 tree text{tree} tree 本身)的加分计算方法如下:

subtree text{subtree} subtree 的左子树的加分 × times × subtree text{subtree} subtree 的右子树的加分 + + + subtree text{subtree} subtree 的根的分数。

若某个子树为空,规定其加分为 1 1 1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

试求一棵符合中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,ldots,n) (1,2,3,…,n) 且加分最高的二叉树 tree text{tree} tree。要求输出

  1. tree text{tree} tree 的最高加分。

  2. tree text{tree} tree 的前序遍历。

输入格式

第 1 1 1 行 1 1 1 个整数 n n n,为节点个数。

第 2 2 2 行 n n n 个用空格隔开的整数,为每个节点的分数

输出格式

第 1 1 1 行 1 1 1 个整数,为最高加分($ Ans le 4,000,000,000$)。

第 2 2 2 行 n n n 个用空格隔开的整数,为该树的前序遍历。

样例 #1 样例输入 #1
5
5 7 1 2 10
样例输出 #1
145
3 1 2 4 5
提示 数据规模与约定

对于全部的测试点,保证 1 ≤ n < 30 1 leq n< 30 1≤n<30,节点的分数是小于 100 100 100 的正整数,答案不超过 4 × 1 0 9 4 times 10^9 4×109。

状 态 表 示 : f [ i ] [ j ] : 从 第 i 个 结 点 到 第 j 个 结 点 作 为 一 个 单 独 的 树 的 最 大 加 分 状态表示:f[i][j]:从第i个结点到第j个结点作为一个单独的树的最大加分 状态表示:f[i][j]:从第i个结点到第j个结点作为一个单独的树的最大加分

转 移 方 程 : f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i ] [ k − 1 ] ∗ f [ k + 1 ] [ j ] + f [ k ] [ k ] ) 转移方程:f[i][j]=max(f[i][j],f[i][k-1]*f[k+1][j]+f[k][k]) 转移方程:f[i][j]=max(f[i][j],f[i][k−1]∗f[k+1][j]+f[k][k])

正确性的证明:

d p dp dp的核心就在于:过去百分百的决定现在,并且这种决定状态能够延伸到未来

我们第一层循环枚举区间长度,这样我们在调用状态 转 移 方 程 : f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i ] [ k − 1 ] ∗ f [ k + 1 ] [ j ] + f [ k ] [ k ] ) 转移方程:f[i][j]=max(f[i][j],f[i][k-1]*f[k+1][j]+f[k][k]) 转移方程:f[i][j]=max(f[i][j],f[i][k−1]∗f[k+1][j]+f[k][k])的时候,其子树的最大加分一定已经被求出来了,因为我们枚举的区间长度是从小到大的,所以满足了过去百分百的决定现在的性质。最后输出 f [ 1 ] [ n ] f[1][n] f[1][n]即可

#include 
using namespace std;
#define int long long
const int N=2*30+5;
int f[N][N];
int root[N][N];
int n;

void print(int l,int r)
{
    int k=root[l][r];
    cout<=l)
    {
        print(l,k-1);
    }

    if (r>=k+1)
    {
        print(k+1,r);
    }

}
signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>f[i][i];
        root[i][i]=i;
    }

    for(int len=1;len
        for(int l=1;l+len<=n;l++)
        {
            int r=l+len;
            for(int k=l;k<=r;k++)
            {
                int val;
                if (k==l)
                {
                    val=f[l+1][r]+f[l][l];
                }
                else if (k==r)
                {
                    val=f[l][r-1]+f[r][r];
                }
                else
                {
                    val=f[l][k-1]*f[k+1][r]+f[k][k];
                }

                if (val>f[l][r])
                {
                    f[l][r]=val;
                    root[l][r]=k;
                }
            }
        }
    }
    cout< 

记忆化搜索:

#include 
using namespace std;
#define int long long
const int N=2*30+5;
int f[N][N];
int root[N][N];
int n;

int search(int l,int r)
{
    if (f[l][r])
    {
        return f[l][r];
    }
    for(int k=l;k<=r;k++)
    {
        int l_val=(k==l?1:search(l,k-1));
        int r_val=(k==r?1:search(k+1,r));

        if (l_val*r_val+f[k][k]>f[l][r])
        {
            f[l][r]=l_val*r_val+f[k][k];
            root[l][r]=k;
        }
    }
    return f[l][r];

}
void print(int l,int r)
{
    int k=root[l][r];
    cout<=l)
    {
        print(l,k-1);
    }

    if (r>=k+1)
    {
        print(k+1,r);
    }

}
signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>f[i][i];
        root[i][i]=i;
    }


    cout<
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935151.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号