news 2025/12/29 19:38:59

leetcode 3562

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
leetcode 3562

3562: 折扣价交易股票的最大利润

注:数据范围说 hierarchy.length == n - 1,且 员工 1 是所有员工的直接或间接上司,所以输入是一个 n 点 n−1 边的连通图,即树。

思路:树上背包 + 状态机 DP

寻找子问题
站在节点 x 上,讨论是否购买 present[x]。设节点 y 是节点 x 的儿子。

如果不买 present[x],且预算至多为 j,那么问题变成:

  • 从 x 的所有子树 y 中能得到的最大利润之和。
  • 所有子树 y 的花费总和必须 ≤j。
  • present[y] 不能半价购买。

如果买 present[x],且预算至多为 j,那么问题变成:

  • 从 x 的所有子树 y 中能得到的最大利润之和,加上买 present[x] 得到的利润。
  • 买 present[x] 花了 cost,其中 cost 等于 present[x](原价买股票)或者 ⌊present[x]/2⌋(半价买股票),取决于 x 的父节点有没有买股票
  • 所有子树 y 的花费总和必须 ≤j−cost。
  • present[y] 可以半价购买。

状态设计和状态转移
dfs(x) 返回一个长为 (budget+1)×2 的二维数组 f,其中 f[j][k] 表示:

  • 从子树 x 中能得到的最大利润之和。
  • 预算为 j,即花费总和 ≤j。
  • k=0 表示 present[x] 不能半价购买,k=1 表示 present[x] 可以半价购买。

首先,计算x 的所有儿子子树 y 的最大利润总和subF[j][k]。枚举 x 的儿子 y:

  • 枚举分配给当前儿子 y 的预算 jy=0,1,2,…,j,那么分配给前面遍历过的儿子的总预算为 j−jy。
  • 用前面遍历过的儿子的收益 subF[j−jy][k] 加上当前儿子 y 的收益 dfs(y)[jy][k],更新 subF[j][k] 的最大值。注意这里用了 0-1 背包的空间优化(倒序遍历 | 至多)

然后,考虑 present[x] 是否购买,计算 f[j][k]:

  • 不买 present[x],那么分配给儿子子树的预算不变,仍然为 j,即 f[j][k]=subF[j][0],这里的 0 是因为对于子树 y 来说,父节点 x 一定不买。
  • 买 present[x],那么分配给儿子子树的预算要扣掉 cost,即 f[j][k]=subF[j−cost][1],这里的 1 是因为对于子树 y 来说,父节点 x 一定买。
vector<vector<int>> g(n); for(auto& e:hierarchy) g[e[0]-1].push_back(e[1]-1);
  • 把输入的hierarchy转成邻接表g[x]表示x的子节点列表。
  • 创建了一个长度为budget + 1的数组,每个元素是一个长度为 2 的int数组,整体可以用f[i][0]f[i][1]来访问。
auto dfs = [&](this auto&& dfs, int x) -> vector<array<int, 2>>
  • 返回一个(budget+1) × 2的表:

    • f[j][0]:父节点没买时,子树x在预算j下的最大利润。

    • f[j][1]:父节点买了时,子树x在预算j下的最大利润。

return dfs(0)[budget][0];递归调用dfs(0),返回一个vector<array<int, 2>>,然后取budget行、0列的值。
vector<array<int, 2>> sub_f(budget + 1);
  • 在上司状态为 k 的条件下只考虑 x 的所有下属(不含 x 本人),能得到的 最大净利润。

  • 对每个子节点y,做分组背包

    • y的子树看作一个「物品组」,体积是jy,价值是fy[jy][k]

    • 倒序枚举预算(类似 0-1 背包)避免重复计算。

vector<array<int, 2>> f(budget + 1);
  • 再决定x自己买不买
return dfs(0)[budget][0];
  • 根没有上司,相当于上司没买(k=0);

  • f[budget][0]即为整棵树在折扣政策下的最大净利润

class Solution { public: int maxProfit(int n, vector<int>& present, vector<int>& future, vector<vector<int>>& hierarchy, int budget) { //建树-下标转换 vector<vector<int>> g(n); for(auto& e:hierarchy) g[e[0]-1].push_back(e[1]-1); auto dfs=[&](this auto&& dfs,int x)->vector<array<int,2>>{ // 计算从 x 的所有儿子子树 y 中,能得到的最大利润之和(x 不买/买) vector<array<int,2>> sub_f(budget+1); for(int y:g[x]){ auto fy=dfs(y); for(int j=budget;j>=0;j--){ // 枚举子树 y 的预算为 jy //看作一个体积为 jy,价值为 fy[jy][k] 的物品 for(int jy=0;jy<=j;jy++){ for(int k=0;k<2;k++){ // k=0: x 不买,k=1: x 买 sub_f[j][k]=max(sub_f[j][k],sub_f[j-jy][k]+fy[jy][k]); } } } } // 计算从子树 x 中,能得到的最大利润之和(x 父节点不买/买) vector<array<int,2>> f(budget+1); for(int j=0;j<=budget;j++){ for(int k=0;k<2;k++){ // k=0: x 父节点不买,k=1: x 父节点买 int cost=present[x]/(k+1); if(j>=cost) f[j][k]=max(sub_f[j][0],sub_f[j-cost][1]+future[x]-cost); else{ //超过预算,只能不买 x f[j][k]=sub_f[j][0]; } } } return f; }; return dfs(0)[budget][0]; } };
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/26 15:39:15

重构智慧书-第18条:实力与实干

一、原文呈现实力与实干要得声名显赫&#xff0c;必须兼有实力与实干精神。有了这两者&#xff0c;显赫的声名就会如虎添翼。有实干精神的平庸之辈比无实千精神的高明之辈更有成就。实干创实绩。肯出大力者必得大名。有的人连最简单的事情也不肯下力去干。干与不干,差不多总与一…

作者头像 李华
网站建设 2025/12/25 10:08:15

读捍卫隐私08智能出行

1. 互联网电话 1.1. 和打印机一样&#xff0c;VoIP电话的系统更新也可以被伪造和接受 1.2. 大多数VoIP电话都有一个免提选项&#xff0c;让你可以在你的隔间或办公室中将某人的通话用扬声器播放 1.2.1. 意味着在电话听筒之外不仅有一个扬声器&#xff0c;还有一个麦克风 1.…

作者头像 李华
网站建设 2025/12/21 21:30:50

媒体专访实录:LobeChat创始人谈开源初心

LobeChat 技术架构深度解析&#xff1a;从容器化部署到插件生态的全栈实践 在大模型浪潮席卷全球的今天&#xff0c;AI 对话系统早已不再是实验室里的概念玩具。从客服机器人到个人助手&#xff0c;自然语言交互正成为数字世界的新入口。然而&#xff0c;当 OpenAI 的 ChatGPT …

作者头像 李华
网站建设 2025/12/22 22:46:02

小喵播放器 1.1.2| 一款支持视频超分的播放器,支持网页视频以及B站番剧

小喵播放器是一款基于mpv播放器内核的本地视频播放器&#xff0c;专为动漫观看场景进行优化。它集成了Anime4K实时超分辨率算法&#xff0c;在播放过程中对低分辨率动画进行画质增强。支持常见视频格式、字幕与音轨切换、播放记录、截图等基础播放器功能&#xff0c;并通过GLSL…

作者头像 李华
网站建设 2025/12/21 20:29:26

LobeChat待办事项提取与提醒功能实现

LobeChat待办事项提取与提醒功能实现 在日常使用聊天工具时&#xff0c;我们常常会随口说一句&#xff1a;“记得提醒我明天开会”或者“下周要交报告”。这些话听起来像是对 AI 的一次普通请求&#xff0c;但如果说完就忘&#xff0c;那它不过是一段被淹没在对话流中的信息碎…

作者头像 李华