NC16681 [NOIP2003]加分二叉树
题目
题目描述
设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分× subtree的右子树的加分+subtree的根的分数
若某个子树为主,规定其加分为1,叶子的加分就是叶节点本身的分数。不考虑它的空子树。 试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。
要求输出:
(1)tree的最高加分
(2)tree的前序遍历
输入描述
第1行:一个整数n(n<30),为节点个数。
第2行:n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出描述
第1行:一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:n个用空格隔开的整数,为该树的前序遍历。
示例1
输入
5 5 7 1 2 10
输出
145 3 1 2 4 5
题解
知识点:DFS,树,区间dp。
因为给出的是中序遍历,因此一个区间可以作为一个树,两个区间加一个中间的点可以作为做左子树根节点和右子树,于是可以区间dp。
设 为区间 构成树后的最高分,有转移方程:
当 时,表示的是空树,应该用 代替。
可以边dp边记录某个树 的父节点 ,因为 本身是作为根节点划分区间。
最后dfs一下 即可。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> #define ll long long using namespace std; int a[37], fa[37][37]; ll dp[37][37]; void dfs(int l, int r) { if (l > r) return; cout << fa[l][r] << ' '; dfs(l, fa[l][r] - 1); dfs(fa[l][r] + 1, r); } int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= n;i++) cin >> a[i], dp[i][i] = a[i], fa[i][i] = i; for (int l = 2;l <= n;l++) { for (int i = 1, j = l;j <= n;i++, j++) { for (int k = i;k <= j;k++) { ll t = max(1LL, dp[i][k - 1]) * max(1LL, dp[k + 1][j]) + a[k]; if (dp[i][j] < t) { dp[i][j] = t; fa[i][j] = k; } } } } cout << dp[1][n] << '\n'; dfs(1, n); return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16589644.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧