算法:树形dp(树状dp)

文章目录

    • 一、树形DP的概念
      • 1.基本概念
      • 2.解题步骤
      • 3.树形DP数据结构
    • 二、典型例题
      • 1.LeetCode:337. 打家劫舍 III
        • 1.1、定义状态转移方程
        • 1.2、参考代码
      • 2.ACWing:285. 没有上司的舞会
        • 1.1、定义状态转移方程
        • 1.2、拓扑排序参考代码
        • 1.3、dfs后序遍历参考代码

一、树形DP的概念

  树形动态规划(Tree DP) 是动态规划在树结构数据上的应用。树是一种特殊的图,具有无环的特点,这使得树形动态规划在很多问题中比普通的动态规划更为直观和高效。在树形DP问题中,通常需要处理与节点相关的状态,并利用树的层次结构,自底向上或自顶向下递归地解决问题。树形DP的学习对线性DP的状态定义也有很大帮助。

1.基本概念

  • 状态表示:树形DP的状态通常与树的节点相关联,每个状态代表了以某节点为根的子树在某种条件下的最优解、计数或其他性质。
  • 状态转移:状态的转移依赖于子节点到父节点(或父节点到子节点)的关系。通常,要解决一个节点的问题,需要先解决它的所有子节点的问题,然后根据子节点的解来更新当前节点的解。或者当前结点的状态由父亲转移而来。

  在树形DP中,如果当前结点的状态由其子节点转移而来,那么可以进行DFS后序遍历,或者拓扑排序顺序遍历(在图中)。比如在关键路径中,提到过,求最长路径可以使用拓扑排序+动态规划来求解,这实际上就很像是一个树形DP。

2.解题步骤

  我们说树形DP的状态转移,实际上比线性DP更直观,因为父子结点之间的关系是很明显的,是从上到下的状态转移还是从下依次往下的状态转移是很明显的。

  1. 定义状态:首先明确每个状态所代表的含义,以及解题需要考虑的所有情况。
  2. 状态转移方程:根据问题的具体条件,找出不同状态之间的关系,形成状态转移方程。这通常涉及对当前节点的处理和对子节点状态的汇总。
  3. 初始化:确定递归的基本情况,即最简单情况下各状态的值,用于终止递归。
  4. 计算顺序:确定状态计算的顺序。在树形DP中,通常需要后序遍历(先处理所有子节点,再处理父节点)来自底向上计算,或者先序遍历来自顶向下传递信息。
  5. 答案提取:根据定义的状态,从根节点或特定节点提取最终答案。

3.树形DP数据结构

线性dp直接可以使用线性数组来存储状态,那么树形DP怎么办呢?

  • 如果真的只跟其亲儿子有关,你可以直接在树上进行DFS后序,利用DFS函数中存储状态,因为这不涉及到记忆化搜索
  • 如果其不仅仅跟其亲儿子有关,你就必须采取一定行动来保存状态信息了(属于一种记忆化搜索)。
  • 你可以先进行一次DFS对树结点编号(或已经有编号),然后再操作。这样你就可以定义dp数组了
  • 你可以对树结点存储在哈希表中来存储该结点状态。这样你就可以定义dp了
  • 如果需要新建图,你可以对树或图,存储其邻接表,并且每个结点多定义一个状态信息即可。若对于一个特定的顶点状态,它跟其邻接表中所有结点有关,如果其邻接表中的顶点状态已经被求出,则可以进行转移。树图不分家。vector实现邻接表
  • ···

二、典型例题

1.LeetCode:337. 打家劫舍 III

模板题
337. 打家劫舍 III
在这里插入图片描述
  父亲最优解跟其子节点最优解有关,因此属于树状dp。由于父亲的最优解不仅跟其亲儿子有关,还跟孙子有关,因此我们在进行树状dp时,不能只DFS后序遍历返回结果,我们还得存储孙子信息,即记忆化搜索,因此我们在书写这个树状dp的时候,需要使用额外空间存储状态,比如在此题中没有给出编号,使用哈希表是最快的。
  但是以上我们所说的状态是单个状态 即 dp[root]表示以root为根的最高金额,如果我们定义的状态dp[root][0]表示不选择root时的最高金额,dp[root][1]表示选择root时的最高金额,那么我们只需要将树返回值是多个值(如结构体),就可以不用多开额外空间了~

1.1、定义状态转移方程
  • dp[root][0]=max(dp[l_child][1],dp[l_child][0])+max(dp[r_child][1],dp[r_child][0]);//不被选择时
  • dp[root][1]=root->val+dp[l_child][0]+dp[r_child][0];//被选择时
    • 根不被选择时,其能得到的最大金额的状态,由其儿子不被选择的最大金额状态以及其儿子被选择的最大金额状态转移而来,因为根不被选择时,其儿子可以被选也可以不被选,让根的金额最大,那么择其最大者就行。
    • 根被选择时,其能得到的最大金额的状态,由其儿子不被选择的最大金额状态转移而来。
1.2、参考代码
class Solution {
public://pair::first表示不被选择时的最大值//pair::second表示被选择时的最大值pair<int,int> TreeDp(TreeNode * root){if(!root) return {0,0};pair<int,int> dp_left=TreeDp(root->left);pair<int,int> dp_right=TreeDp(root->right);pair<int,int> dp_root;//不被选择时dp_root.first=max(dp_left.first,dp_left.second)+max(dp_right.first,dp_right.second);//被选择时dp_root.second=root->val+dp_left.first+dp_right.first;return dp_root;}int rob(TreeNode* root) {pair<int,int> ans=TreeDp(root);return max(ans.first,ans.second);}
};

2.ACWing:285. 没有上司的舞会

模板题
285. 没有上司的舞会
在这里插入图片描述
  这题和 打家劫舍 III 基本上一摸一样呀,只不过这里可能是图,并且acwing需要自己构建结点,因此这里可以提供更多建树dp思路。

没有职员愿意和直接上司一起参会。实际上就是指相邻父子结点不能同时被选择。

1.1、定义状态转移方程

  这里我们的状态和打家劫舍III的状态一模一样。不过我们可以使用拓扑排序的方式实现,只需要存储fa数组,表示父节点,因为根结点的状态由子节点转移而来,并且没必要按顺序转移~。用邻接表存图,然后按照打家劫舍III dfs实现会简单很多。

1.2、拓扑排序参考代码
#include<bits/stdc++.h>
using namespace  std;
int main(void){ios_base::sync_with_stdio(false);cin.tie(0);int N;cin>>N;vector<int> fa(N+1,-1);//拓扑排序方法 找寻前驱用vector<int> degree(N+1,0);//用于拓扑排序删除度的数组vector<pair<int,int>> dp(N+1);//dp状态数组,second表示被选择,first表示不被选择。for(int i=1;i<=N;++i) {cin>>dp[i].second;dp[i].first=0;}for(int i=1;i<N;++i){int son,Fa;cin>>son>>Fa;fa[son]=Fa;degree[Fa]++;}//为了和打家劫舍不一样,我们这里采用拓扑排序的方式//如果仍然用dfs,则需要找到根结点,dfs会方便很多,也不需要fa数组了stack<int> sta;for(int i=1;i<=N;++i){if(degree[i]==0){sta.push(i);}}int ans=0;while(!sta.empty()){int cur=sta.top();sta.pop();if(fa[cur]!=-1) {dp[fa[cur]].first += max(dp[cur].first, dp[cur].second);dp[fa[cur]].second += dp[cur].first;if (--degree[fa[cur]] == 0) sta.push(fa[cur]);}elseans=max(ans,max(dp[cur].first,dp[cur].second));}cout<<ans;return 0;
}
1.3、dfs后序遍历参考代码
#include<bits/stdc++.h>
using namespace  std;
vector<vector<int> > g;
vector<pair<int,int>> dp;//dp状态数组,second表示被选择,first表示不被选择。
void dfs(int root){for(int i=0;i<g[root].size();++i){dfs(g[root][i]);dp[root].second+=dp[g[root][i]].first;dp[root].first+=max(dp[g[root][i]].first,dp[g[root][i]].second);}return;
}
int main(void){ios_base::sync_with_stdio(false);cin.tie(0);int N;cin>>N;g.assign(N+1,vector<int>{});dp.assign(N+1,{});//dp状态数组,second表示被选择,first表示不被选择。unordered_set<int> roots;//用于保存根for(int i=1;i<=N;++i) {cin>>dp[i].second;dp[i].first=0;roots.insert(i);}for(int i=1;i<N;++i){int son,Fa;cin>>son>>Fa;g[Fa].emplace_back(son);roots.erase(son);}int ans=0;for(auto & i:roots){dfs(i);ans+=max(dp[i].first,dp[i].second);//从不同根遍历}cout<<ans;return 0;
}

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

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

相关文章

刷题之Leetcode209题(超级详细)

209.长度最小的子数组 力扣题目链接(opens new window)https://leetcode.cn/problems/minimum-size-subarray-sum/ 给定一个含有 n 个正整数的数组和一个正整数 s &#xff0c;找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组&#xff0c;并返回其长度。如果不存在符合条…

数据可视化高级技术Echarts(快速上手柱状图进阶操作)

目录 1.Echarts的配置 2.程序的编码 3.柱状图的实现&#xff08;入门实现&#xff09; 相关属性介绍&#xff08;进阶&#xff09;&#xff1a; 1.标记最大值/最小值 2.标记平均值 3.柱的宽度 4. 横向柱状图 5.colorBy series系列&#xff08;需要构造多组数据才能实现…

以动态库链接库 .dll 探索结构体参数

Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 在写dll 插件中发现的函数指针用途和 typedef 的定义指针的用法-CSDN博客 两步之后&#xff0c;尝试加入结构体实现整体数据使用。 注意结构体 Ak 是相同的 代码如下 DLL文件有两个&#xff0c;dll.dll是上面提到…

C-偶遇行军蚁(遇到过的题,做个笔记)

我的代码: 思路就是把每一行看成一个字符串&#xff0c;然后逐渐增加字符就行 #include <iostream> #include <vector> using namespace std; int main() {string s;int n;cin >> n; //读入行数cin >> s; //读入字符串vector<string>arr(n…

一点点金融

一点点金融 价值投资 需求 > 有限 > 不可逆 > 优势 > 长期持有者多趋势分析 改进MACD策略&#xff0c;使用涨跌幅比值RSI计算MACD原始MACD计算改进思路&#xff1a;使用涨跌幅比值RSI计算MACD 价值投资 需求 > 有限 > 不可逆 > 优势 > 长期持有者多…

[pyenv] 1. 安装与使用

在看了几个开源的python环境管理器的评论后, 我打算入手 pyenv, 该项目有以下几个优势: 该项目使用纯shell脚本语言实现, 天然亲和linux开发环境.通过设置的PATH环境变量和shims方法隔离的实现方案非常轻量化.子命令引入了compgen补全功能, 对命令输入操作友好.源码开源, 可扩展…

《pytorch深度学习实战》学习笔记第2章

第2章 预训练网络 讨论3种常用的预训练模型&#xff1a; 1、根据内容对图像进行标记&#xff08;识别&#xff09; 2、从真实图像中生成新图像&#xff08;GAN&#xff09; 3、使用正确的英语句子来描述图像内容&#xff08;自然语言&#xff09; 2.1 获取一个预训练好的网络…

通过 Cookie、Redis共享Session 和 Spring 拦截器技术,实现对用户登录状态的持有和清理(三)

本篇内容对应 “2.4 生成验证码” 小节 和 “4.7 优化登陆模块”小节 视频链接 1 Kaptcha介绍 Kaotcga是一个生成验证码的工具。 你的网站验证码是什么&#xff1f; 在我们这个牛客论坛项目&#xff0c;验证码分为两部分 给用户看的是图片&#xff0c;用户根据图片上显示的…

什么牌子开放式耳机好用?优选五大高分好物真诚分享

对于习惯长时间佩戴耳机的朋友来说&#xff0c;入耳式耳机固然能够提供较优质的音质体验。但是&#xff0c;由于其较为封闭的设计以及对耳洞的压迫&#xff0c;舒适感较差&#xff0c;长时间佩戴可能会对听力造成一定的影响。因此&#xff0c;开放式耳机的出现为音乐发烧友们提…

Leetcode 684. 冗余连接

心路历程&#xff1a; 这道题属于图论的经典连通问题&#xff0c;这道题翻译过来就是&#xff0c;找到破开图中环的一条边&#xff1b;再翻译过来就是&#xff0c;从后往前遍历edges&#xff0c;依次连接边&#xff0c;当发现新连接的边已经有相同父节点时&#xff08;已经马上…

基于单片机风力发电机迎风面对风向的追踪系统设计

**单片机设计介绍&#xff0c;基于单片机风力发电机迎风面对风向的追踪系统设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机风力发电机迎风面对风向的追踪系统设计是一个涉及单片机编程、传感器技术、机械控制等多个领域的综…

java日志框架简介

文章目录 概要常用日志框架常见框架有以下&#xff1a;slf4j StaticLoggerBinder绑定过程&#xff08;slf4j-api-1.7.32 &#xff09;JCL 运行时动态查找过程&#xff1a;&#xff08;commons-logging-1.2&#xff09;使用桥接修改具体日志实现 一行日志的打印过程开源框架日志…

面试算法-153-旋转图像

题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,…

Java项目:基于Springboot+vue实现的医院住院管理系统设计与实现(源码+数据库+开题报告+任务书+毕业论文)

一、项目简介 本项目是一套基于Springbootvue实现的医院住院管理系统设 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简…

基于Springboot+Vue实现前后端分离社团管理系统

一、&#x1f680;选题背景介绍 &#x1f4da;推荐理由&#xff1a; 21世纪时信息化的时代&#xff0c;几乎任何一个行业都离不开计算机&#xff0c;将计算机运用于社团管理也是十分常见的。过去使用手工的管理方式对大学生社团进行管理&#xff0c;造成了管理繁琐、难以维护等…

基于java+SpringBoot+Vue的房屋租赁系统设计与实现

基于javaSpringBootVue的房屋租赁系统设计与实现 开发语言: Java 数据库: MySQL技术: Spring Boot JSP工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 房源浏览模块&#xff1a;展示可租赁的房源信息&#xff0c;用户可以根据条件筛选房源。 预约看房模块&#…

java项目基于Springboot和Vue的高校心理教育辅导系统的设计与实现

今天要和大家聊的是基于Springboot和Vue的高校心理教育辅导系统的设计与实现 &#xff01;&#xff01;&#xff01; 有需要的小伙伴可以通过文章末尾名片咨询我哦&#xff01;&#xff01;&#xff01; &#x1f495;&#x1f495;作者&#xff1a;李同学 &#x1f495;&…

springboot实战---5.最简单最高效的后台管理系统开发

&#x1f388;个人主页&#xff1a;靓仔很忙i &#x1f4bb;B 站主页&#xff1a;&#x1f449;B站&#x1f448; &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;SpringBoot &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&…

安达发|APS软件在皮具箱包生产工艺中的应用

APS软件&#xff0c;即高级生产计划排程系统&#xff08;Advanced Planning and Scheduling&#xff09;&#xff0c;在皮具箱包生产工艺中的应用至关重要。它通过高效的生产计划和资源优化&#xff0c;帮助企业降低成本、提高生产效率和市场响应速度。以下是APS软件在皮具箱包…

day03-Docker

1.初识 Docker 1.1.什么是 Docker 1.1.1.应用部署的环境问题 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰到一些问题&#xff1a; 依赖关系复杂&#xff0c;容易出现兼容性问题开发、测试、生产环境有差异 例如一个项目中&#xff0c;部署时需要依…