NOIP2003提高组第二轮T3:加分二叉树

题目链接

[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 个整数,为最高加分( A n s ≤ 4 , 000 , 000 , 000 Ans \le 4,000,000,000 Ans4,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 1n<30,节点的分数是小于 100 100 100 的正整数,答案不超过 4 × 1 0 9 4 \times 10^9 4×109

算法思想

最高加分

根据题目描述:

  • 一棵二叉树的中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,\ldots,n) (1,2,3,,n)

在中序遍历中,一旦确定了根结点,那么左右子树的节点编号一定在根结点两侧,例如当根节点为 3 3 3时,那么左子树的结点编号为 1 , 2 1,2 1,2,右子树的结点编号为 4 , 5 , … , n 4,5,\ldots, n 4,5,,n,如下图所示:

在这里插入图片描述

  • 加分计算方法为左子树的加分 × \times × 右子树的加分 + + +根的分数。

求一棵符合中序遍历为 ( 1 , 2 , 3 , … , n ) (1,2,3,\ldots,n) (1,2,3,,n) 且加分最高的二叉树,就是求以根节点为中心,将左右两个区间(子树)合并在一起的最大值,因此可以使用区间型动态规划进行处理。

状态表示

f [ i , j ] f[i,j] f[i,j]表示二叉树中序遍历的节点编号在区间 [ i , j ] [i,j] [i,j]的最大加分分值。

状态计算

从最后一个合并位置,也就是根节点的位置可以将状态计算分为下面几种情况:

  • 根节点在 i i i位置,此时左子树为空,加分为 1 × 1\times 1×,得到的分数为 1 × f [ i + 1 ] [ j ] + w [ i ] 1\times f[i+1][j]+w[i] 1×f[i+1][j]+w[i]
  • 根节点在 i + 1 i+1 i+1位置,得到的分数为 f [ i ] [ i ] × f [ i + 2 ] [ j ] + w [ i + 1 ] f[i][i]\times f[i+2][j]+w[i+1] f[i][i]×f[i+2][j]+w[i+1]
  • 根节点在 k k k位置,得到的分数为 f [ i ] [ k − 1 ] × f [ k + 1 ] [ j ] + w [ k ] f[i][k-1]\times f[k+1][j]+w[k] f[i][k1]×f[k+1][j]+w[k]
  • 根节点在 j j j位置,此时右子树为空,加分为 1 × 1\times 1×,得到的分数为 f [ i ] [ j − 1 ] × 1 + w [ j ] f[i][j-1]\times 1+w[j] f[i][j1]×1+w[j]

这里 w [ i ] w[i] w[i]表示第 i i i个节点的分数。 f [ i ] [ j ] f[i][j] f[i][j]要取以上情况的最大值。

初始状态

  • 空树其加分为 1 1 1,也就是说 f [ i ] [ i − 1 ] = 1 f[i][i-1]=1 f[i][i1]=1(或者 f [ i + 1 ] [ i ] = 1 f[i+1][i]=1 f[i+1][i]=1
  • 如果区间只有一个节点,那么分值就是当前节点的分数,即 f [ i ] [ i ] = w [ i ] f[i][i]=w[i] f[i][i]=w[i]

时间复杂度

状态数为 n × n n\times n n×n,状态计算需要枚举根节点的位置 1 1 1 ~ n n n,时间复杂度为 O ( n 3 ) O(n^3) O(n3)

前序遍历

为了找到最大加分的前序遍历,就要在区间 [ i , j ] [i,j] [i,j]中找到一个根节点 k k k使得 f [ i ] [ k − 1 ] × f [ k + 1 ] [ j ] + w [ k ] f[i][k - 1]\times f[k+1][j]+w[k] f[i][k1]×f[k+1][j]+w[k]等于 f [ i ] [ j ] f[i][j] f[i][j]

对于前序遍历要先输出根节点 k k k,然后在递归遍历左子树( [ i , k − 1 ] [i,k-1] [i,k1])和右子树( [ k + 1 , j ] [k+1,j] [k+1,j])即可。

注意,如果 i i i j j j相等,说明是叶子节点,其子树的根节点就是自己。

代码实现

#include <iostream>
using namespace std;
const int N = 50;
int w[N], f[N][N];
int n;
//求区间[i,j]的前序遍历
void dfs(int i, int j)
{if(i > j) return; //空二叉树if(i == j) cout << i << " "; //叶子节点else{//枚举根节点for(int k = i; k <= j; k ++){//如果以k为根节点取得加分最大值if(f[i][j] == f[i][k - 1] * f[k + 1][j] + w[k]) {cout << k << " "; //输出根节点dfs(i, k - 1); //递归遍历左子树dfs(k + 1, j); //递归遍历右子树break;}}}
}int main()
{cin >> n;for(int i = 1; i <= n; i ++) cin >> w[i];//空树的加分为1for(int i = 1; i <= n + 1; i ++) f[i][i - 1] = 1;//枚举合并长度for(int len = 1; len <= n; len ++){//枚举开始位置for(int i = 1; i + len - 1 <= n; i ++){int j = i + len - 1; //结束位置if(len == 1) f[i][i] = w[i]; //初始状态else{//枚举其它根节点的位置for(int k = i; k <= j; k ++)f[i][j] = max(f[i][j], f[i][k - 1] * f[k + 1][j] + w[k]);}            }}cout << f[1][n] << '\n';dfs(1, n);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/211869.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做流体分析需要知道的两大核心问题:内流和外流

SOLIDWORKS Flow Simulation 是直观的流体力学 (CFD) 分析软件&#xff0c;可以快速轻松的分析产品内部或外部流体的流动情况&#xff0c;以用来改善产品性能和功能。SOLIDWORKS Flow Simulation将专业的流体分析进行功能优化&#xff0c;让普通机械设计师也能进行流体力学分析…

新一代网络监控技术——Telemetry

一、Telemetry的背景 传统的网络设备监控方式有SNMP、CLI、Syslog、NetStream、sFlow&#xff0c;其中SNMP为主流的监控数据方式。而随着网络系统规模的扩大&#xff0c;网络设备数量的增多&#xff0c;网络结构的复杂&#xff0c;相应监控要求也不断提升&#xff0c;如今这些…

Selenium实现多页面切换

当使用 Selenium 进行自动化测试或爬取数据时&#xff0c;有时需要处理多个页面之间的切换。以下是一些可能需要多页面切换的情况&#xff1a; 1、打开新窗口/页面&#xff1a; 在当前页面上点击链接、按钮或执行某些操作时&#xff0c;可能会打开一个新的窗口或页面。此时&a…

【性能优化】JVM调优与写出JVM友好高效的代码

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…

U-boot(四):start_armboot

本文主要探讨210的uboot启动的第二阶段&#xff0c;主要函数为start_armboot。 uboot 一阶段初始化SoC内部部件(看门狗、时钟等),初始化DDR,重定位 二阶段初始化其余硬件(iNand、网卡芯片)以及命令、环境变量等 启动打印硬件信息,进入bootdelay,读秒完后执行bootc…

2002-2020年341个地级市农业保险收入数据

2002-2020年341个地级市农业保险收入数据 1、时间&#xff1a;2002-2020年 2、范围&#xff1a;341个地级市 3、指标&#xff1a;农业保险收入 4、来源&#xff1a;整理自wind、保险年鉴 5、指标解释&#xff1a; 农业保险保费收入是指保险公司从农户或农业生产经营者那里…

使用Arrays.Sort并定制Comparator排序解决合并区间

合并区间-力扣算法题56题 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&am…

rabbit MQ的延迟队列处理模型示例(基于SpringBoot死信模式)

说明&#xff1a; 生产者P 往交换机X&#xff08;typedirect&#xff09;会发送两种消息&#xff1a;一、routingKeyXA的消息&#xff08;消息存活周期10s&#xff09;&#xff0c;被队列QA队列绑定入列&#xff1b;一、routingKeyXB的消息&#xff08;消息存活周期40s&#xf…

uboot中nfs和tftp方式获取文件

NFS文件系统挂载 服务器端配置如下 1.Server端需要安装NFS服务&#xff1a; sudo apt-get install nfs-kernel-server2.创建需要挂载的路径&#xff1a; mkdir -p /home/workspace/mercury/nfs_path3.创建共享目录&#xff1a; ①vim /etc/exports ②在文件中添加&#xff…

Vue3 封装组件库并发布到npm仓库

一、创建 Vue3 TS Vite 项目 输入项目名称&#xff0c;并依次选择需要安装的依赖项 npm create vuelatest 项目目录结构截图如下&#xff1a; 二、编写组件代码、配置项和本地打包测试组件 在项目根目录新建 package 文件夹用于存放组件 &#xff08;以customVideo为例&a…

在 CentOS 7 上安装 MySQL 8

在 CentOS 7 上安装 MySQL 8 步骤 1: 添加 MySQL Yum 存储库 首先&#xff0c;我们需要添加 MySQL Yum 存储库。打开终端并执行以下命令&#xff1a; sudo yum install -y https://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm步骤 2: 导入 MySQL GPG 公钥 …

Redis报错:JedisConnectionException: Could not get a resource from the pool

1、问题描述&#xff1a; redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool 2、简要分析&#xff1a; redis.clients.util.Pool.getResource会从JedisPool实例池中返回一个可用的redis连接。分析源码可知JedisPool 继承了 r…