2021.06.03加分二叉树

2021.06.03加分二叉树

题目描述

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

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

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

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

tree 的最高加分。

tree 的前序遍历。

输入格式

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

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

输出格式

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

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

样例输入

5
5 7 1 2 10

样例输出

145
3 1 2 4 5

数据规模和约定

1≤n<30,节点的分数是小于 100 的正整数,答案不超过 4 × 1 0 9 4 \times 10^9 4×109

思路

由于其说明了中序遍历顺序,所以可以采用线段树+区间dp

  1. 动规思路:
    由于二叉树的分数只和谁为根有关,所以我们需要穷举所有跟的情况。
    先从根部开始向上dp,即考虑区间长度为1,一直遍历到长度为n-1.
  2. 定义状态:
    dp[i][j]: 第i个节点到第j个节点生成数的最大得分
  3. 状态转移:
    穷举根的所有情况:k∈[i,j],dp[i][j] = max{ dp[i][k-1]*dp[k+1][j] + dp[k][k] }
    4.线段树的先序遍历:
        void pre(int l, int r) { //线段树的遍历函数
            if(r < l) return;
            System.out.print(root[l][r]+" ");
            if(l == r) return;
            pre(l, root[l][r]-1);
            pre(root[l][r]+1, r);
        }

代码

    class Solution{ 
        int MAXLEN = 50;
        int[][] root = new int[MAXLEN][MAXLEN];
        int[][] dp = new int[MAXLEN][MAXLEN]; //dp[i][j]:为节点i到节点j生成树的最大分数
        int n;
        void test() {
            Scanner cin = new Scanner(System.in);
            n = cin.nextInt();
            for(int i = 1; i <= n; i++) {
                dp[i][i] = cin.nextInt(); //dp[i][i]记录着根节点的值
                dp[i][i-1] = 1;
                root[i][i] = i;
            }
            for(int len = 1; len < n; len++) {
                for(int i = 1; i + len <= n; i++) {
                    int j = i+len; //另一节点j
                    dp[i][j] = dp[i][i] + dp[i+1][j]; //默认左子树为空
                    root[i][j] = i; 
                    for(int k = i+1; k < j; k++) { //遍历根
                        if( dp[i][j] < dp[i][k-1]*dp[k+1][j] + dp[k][k] ) {
                            dp[i][j] = dp[i][k-1]*dp[k+1][j] + dp[k][k];
                            root[i][j] = k;
                        }
                    }
                }
            }
            //注意,遍历完后,root矩阵种不仅仅存放着所求二叉树的信息,而是存放着遍历过程中所有可能的树形。
            System.out.println(dp[1][n]);
            pre(1,n);
        }
        
        void pre(int l, int r) { //线段树的遍历函数
            if(r < l) return;
            System.out.print(root[l][r]+" ");
            if(l == r) return;
            pre(l, root[l][r]-1);
            pre(root[l][r]+1, r);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 二叉树的递归遍历: 二叉树的递归遍历是指通过递归方法遍历二叉树的各个节点,按照某种次序访问每个节点。常见的二叉树遍历方式有前序遍历、中序遍历和后序遍历。 2. 二叉树的非递归遍历: 二叉树的非递归遍历是指通过循环等非递归方法遍历二叉树的各个节点,按照某种次序访问每个节点。非递归遍历需要借助栈来实现,常见的二叉树遍历方式有前序遍历、中序遍历和后序遍历。 3. 二叉树的层次遍历: 二叉树的层次遍历是指按照从上到下、从左到右的顺序遍历每一层节点。常用的方法是使用队列来实现,首先将根节点入队列,然后依次出队列,并将其左右子节点入队列,直到队列为空。 4. 输出二叉树上所有叶节点: 二叉树上的叶节点是指没有子节点的节点。可以通过递归方式,对每个节点进行判断,如果该节点没有左右子节点,则将该节点输出。 5. 求二叉树的高度: 二叉树的高度是指从根节点到叶节点最长路径上经过的边。可以通过递归方式求解,从左右子树中选取较大的一个加上根节点即可。 6. 二叉树层序生成算法二叉树层序生成算法是指按照从上到下、从左到右的顺序依次生成每个节点。可以使用队列来实现,首先将根节点入队列,然后依次出队列,并根据当前节点生成其左右子节点,将其入队列,直到生成完所有节点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值