洛谷P1040. 加分二叉树
题目描述
设一个 tree
的中序遍历为(
每个节点都有一个分数(均为正整数),记第 tree
及它的每个子树都有一个加分,任一棵子树 subtree
(也包含 tree
本身)的加分计算方法如下:
subtree
的左子树的加分 subtree
的右子树的加分 subtree
的根的分数
若某个子树为空,规定其加分为
叶子的加分就是叶节点本身的分数,不考虑它的空子树。
试求一棵符合中序遍历为(tree
。
要求输出:
(1)tree
的最高加分
(2)tree
的前序遍历
输入格式
第
第
输出格式
第 int
范围)。
第
解题思路
状态表示
状态计算
状态统计
补充:二叉树的前序遍历,先输出根,再递归左子,再递归右子。
然后在输出的时候递归处理:
void print(int l, int r)
{
if (l > r) return ; // 不构成节点
int k = g[l][r]; // 根节点
printf("%d ", k);
print(l, k - 1), print(k + 1, r); // 分别递归左右子
}
代码
会贴两份,递推
递推DP
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50;
int f[N][N], g[N][N], n, w[N];
void print(int l, int r)
{
if (l > r) return ; // 不构成节点
int k = g[l][r]; // 根节点
printf("%d ", k);
print(l, k - 1), print(k + 1, r); // 分别递归左右子
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
memset(f, 0xcf, sizeof f);
for (int i = 1; i <= n; i ++ )
g[i][i] = i, f[i][i] = w[i]; // 长度为1的叶子节点分数和根的初始化
for (int len = 2; len <= n; len ++ ) //长度为1的初始化过了,从2开始
{
for (int l = 1, r = l + len - 1; r <= n; l ++, r ++ ) //枚举左端点和右端点
{
for (int k = l; k <= r; k ++ ) // 枚举断点
{
int &v = f[l][r], u, L, R;
L = (k == l) ? 1 : f[l][k - 1]; // 如果k == l代表没有左子树,左分数为1
R = (k == r) ? 1 : f[k + 1][r]; // 如果k == r代表没有右子树
u = L * R + w[k]; // 分数计算
if (u > v) v = u, g[l][r] = k; // 更新信息
}
}
}
printf("%d\n", f[1][n]);
print(1, n);
return 0;
}
记忆化搜索
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 50;
int w[N], f[N][N], g[N][N], n;
int dp(int l, int r)
{
int &v = f[l][r];
if (~v) return v; // 算过的直接调用
if (l == r) return g[l][r] = l, f[l][r] = w[l]; // 叶子节点的处理
for (int k = l; k <= r; k ++ )
{
int u, L, R;
L = (k == l) ? 1 : dp(l, k - 1); // 如果k == l代表没有左子树,左分数为1
R = (k == r) ? 1 : dp(k + 1, r); // 右子同理
u = L * R + w[k];
if (u > v) g[l][r] = k, v = u;
}
return v;
}
void print(int l, int r)
{
if (l > r) return ;
int k = g[l][r];
printf("%d ", k);
print(l, k - 1), print(k + 1, r);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
memset(f, -1, sizeof f);
printf("%d\n", dp(1, n));
print(1, n);
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业