首页 > 其他分享 >P1040 [NOIP2003 提高组] 加分二叉树

P1040 [NOIP2003 提高组] 加分二叉树

时间:2024-10-23 16:00:25浏览次数:1  
标签:遍历 NOIP2003 int text 中序 tree P1040 二叉树 dp

P1040 [NOIP2003 提高组] 加分二叉树

题目描述

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

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

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

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

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

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

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

解法

因为中序遍历保证是 \(1 \to n\),所以可以从这里入手。中序遍历中,如果一个数是这颗子树的根,那么中序遍历的序列以这个数为分割点的左边是左子树,右边是右子树。

我们考虑区间 \(dp\),设计状态 \(dp_{i,j}\) 表示中序遍历中 \(i \to j\) 区间的组成的子树所可能得到分数的最大值。

则有状态转移方程:

\[dp_{i,j} = \max^{j}_{k = i}\{dp_{i,k - 1} \times dp_{k + 1,j} + dp_{k,k}\} \]

那么第一问就做完了。

我们可以在转移的时候加一个判断,用 \(rt_{i,j}\) 表示 \(i \to j\) 中取得最大值是这个区间的根的编号。

用代码表示就是:

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];
	rt[i][j] = k;
}

题目要求输出前序遍历,则递归输出即可。

code:

#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int MAXN = 35;
int n;
int val[MAXN];
int dp[MAXN][MAXN];
int rt[MAXN][MAXN];
void print(int l,int r){
	if(l > r) return;
	cout << rt[l][r] << " ";
	print(l,rt[l][r] - 1);
	print(rt[l][r] + 1,r);
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n;
	for(int i = 0;i <= MAXN - 1;i++){
		for(int j = 0;j <= MAXN - 1;j++){
			dp[i][j] = 1;
		}
	}
	for(int i = 1;i <= n;i++) cin >> val[i],dp[i][i] = val[i];
	for(int i = 1;i <= n;i++) rt[i][i] = i;+
	for(int len = 2;len <= n;len++){
		for(int i = 1;i <= n - len + 1;i++){
			int j = i + len - 1;
			for(int k = i;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];
					rt[i][j] = k;
				}
			}
		}
	}
	cout << dp[1][n] << endl;
	print(1,n);
	return 0;
}

标签:遍历,NOIP2003,int,text,中序,tree,P1040,二叉树,dp
From: https://www.cnblogs.com/wyl123ly/p/18496602

相关文章

  • 全局平衡二叉树学习笔记
    先挂一张jijidawang的图所以学这玩意就是被TopTree薄纱的有人把这玩意叫静态的LCT,然而可能只需要一些LCT的知识,并不需要会LCT。起码我不会注意这叫GBT,不叫GPT,能聊天的那个是CatGPT,不是CatGBT。前置知识:树链剖分用途\(O(\logn)\)处理树上链修改、链查询、子树修改、子树查......
  • 10/22二叉树 求度为1的结点个数
    includeusingnamespacestd;typedefstructBiNode{chardata;structBiNode*lchild,*rchild;}BiTNode,*BiTree;voidCreateBiTree(BiTree&T)//创建一个二叉树{charch;cin>>ch;if(ch=='#')T=NULL;else{T=newBiTNode;T->da......
  • 10.22随笔,二叉树求度为一的节点的个数
    今天去健身房锻炼了身体这是关于二叉树如何求度为一的节点的个数,同理还能求度为零和二的,不难。还又复习了一遍前序中序后续的遍历方法,已经可以由任意两种推出二叉树结构了,不过二叉树的样子和模式我还是有点不太能和代码结合去理解,还需要多加练习include<stdio.h>include<std......
  • 计算法统计二叉树中度为1的节点个数
    最近学习有关于二叉树类的知识,学习时使用的是C语言。代码如下:include<stdio.h>include<stdlib.h>//添加这一行,包含malloc的声明typedefstructTreeNode{intval;structTreeNode*left;structTreeNode*right;}TreeNode;//创建树节点TreeNode*createNode(in......
  • 统计二叉树中度为1的结点个数
    `classTreeNode{intval;TreeNodeleft;TreeNoderight;TreeNode(intval){this.val=val;this.left=null;this.right=null;}}classBinaryTree{publicstaticintcountNodesWithDegreeOne(TreeNoderoot){if(root==null){return0;......
  • PTA 生成格雷码 | C++ | 二叉树
    格雷码是一种包含2n个数串的序列,这种序列:1不存在重复的元素,2每个元素都是长度为n的二进制数串,3相邻元素只有一位不同。例如,长度为23的格雷码为:000,001,011,010,110,111,101,100。请使用分治法构造格雷码。提示,使用分治法构造格雷码,详见百度百科。输入格式:输入一个正整数n(1<=......
  • 二叉树习题其三-Java【力扣】【算法学习day.10】
    前言书接上篇文章二叉树习题其二,这篇文章我们将基础拓展###我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!!习题1.从中序与后序遍历序......
  • leetcode:二叉树oj题
    目录1.单值二叉树2.相同的树3.对称二叉树4.二叉树的前序遍历5.二叉树的中序遍历6.二叉树的后序遍历1.单值二叉树https://leetcode.cn/problems/univalued-binary-tree/description/        对于这道题,我们可以进行深度优先查找,当值相同时就继续向下查找......
  • dfs题目:平衡二叉树(java)
    平衡二叉树题目思路开始的error代码(最后一行return的地方有误)修正的代码题目链接:平衡二叉树题目题目思路用分治的思想,要想看看以root为根节点的二叉树是不是平衡二叉树,得看他的左子树和右子树是不是平衡二叉树,如果左子树和右子树都是平衡的,且root自己是平衡的......
  • Leecode热题100-101.对称二叉树
    给你一个二叉树的根节点 root ,检查它是否轴对称。示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:false提示:树中节点数目在范围 [1,1000] 内-100<=Node.val<=100进阶:你可以运用递归和迭代两种方法解决这个问......