• [NOIp2003] 加分二叉树


    Description

    设一个n个节点的二叉树tree的中序遍历为(1,2,3,…,n),其中数字1,2,3,…,n为节点编号。

    每个节点都有一个分数(均为正整数),记第i个节点的分数为(d_i),tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:

    subtree的左子树的加分 × subtree的右子树的加分 + subtree的根的分数

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

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

    要求输出:

    (1)tree的最高加分

    (2)tree的前序遍历

    Input

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

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

    Output

    第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。

    第2行:n个用空格隔开的整数,为该树的前序遍历。如果存在多种方案,则输出字典序最小的方案。

    Sample Input

    5
    5 7 1 2 10
    

    Sample Output

    145
    3 1 2 4 5
    

    Hint

    (n < 30)

    题解

    题目给定了一棵中序遍历的树,要我们求给定了一定计算方式后最大的前序遍历的树

    我用的是(DP),用(f[i][j])表示([i,j])这个闭区间构成的一棵中序遍历树的最大值

    这显然就变成了一个区间合并问题

    状态转移方程为(f[i][j]=max(f[i][k-1]*f[k+1][j]+a[k]))(k)枚举闭区间([i,j])的根,显然(kepsilon [i,j])

    再考虑边界条件,(f[i][j])代表的为叶子结点,(f[i][i-1])代表空子树,根据题意,于是就有了(f[i][i]=a[i],f[i][i-1]=1)

    最终题目要输出前序遍历,于是我们加一个(root[i][j])数组记录使(f[i][j])最大的(k)(即根的下标),放在循环里面就可以了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    
    const int N=50;
    int n,a[N],f[N][N],root[N][N];
    
    void Output(int l,int r)
    {
        if(l>r) return;
        if(l==r) {printf("%d ",l); return;}
        printf("%d ",root[l][r]);
        Output(l,root[l][r]-1),Output(root[l][r]+1,r);
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%d",&a[i]);
        for(int i=0;i<=n+1;++i)
            f[i][i]=a[i],f[i][i-1]=1;
        for(int i=n;i>=1;--i)
            for(int j=i+1;j<=n;++j)
                for(int k=i;k<=j;++k)//枚举[i,j]这个闭区间内的根
                    if(f[i][j]<(f[i][k-1]*f[k+1][j]+a[k]))
                    {
                        f[i][j]=f[i][k-1]*f[k+1][j]+a[k];
                        root[i][j]=k;
                    }
        printf("%d
    ",f[1][n]);
        Output(1,n);
        return 0;
    }
    
  • 相关阅读:
    Android 颜色配置表-颜色类
    Android模拟器——Genymotion
    Android-adb shell 读取手机系统文件
    android webview js交互 第一节 (java和js交互)
    Android源码目录结构详解(转载)
    BlockingQueue深入分析(转)
    RUDP之三 —— Virtual Connection over UDP
    RUDP之二 —— Sending and Receiving Packets
    OSS层基础:平台区分
    RUDP之一 —— UDP VS TCP
  • 原文地址:https://www.cnblogs.com/hihocoder/p/12375268.html
Copyright © 2020-2023  润新知