【算法】树形DP③ 监控二叉树 ⭐(二叉树染色二叉树灯饰)!

文章目录

  • 前期知识 & 相关链接
  • 例题
    • 968. 监控二叉树
      • 解法1——标记状态+贪心
      • 解法2——动态规划
  • 相关练习题目
    • P2458 [SDOI2006] 保安站岗⭐(有多个儿子节点)🚹
    • LCP 34. 二叉树染色⭐(每个节点 单独dp[k + 1]数组)
    • LCP 64. 二叉树灯饰⭐⭐⭐⭐⭐

前期知识 & 相关链接

树形DP:监控二叉树【基础算法精讲 25】


相关链接:
【算法】树形DP ①(树的直径)
【算法】树形DP ② 打家劫舍Ⅲ(树上最大独立集)

本文中的四道题目都很重要!

例题

968. 监控二叉树

https://leetcode.cn/problems/binary-tree-cameras/solutions/2452795/shi-pin-ru-he-si-kao-shu-xing-dpgai-chen-uqsf/

在这里插入图片描述

提示:
给定树的节点数的范围是 [1, 1000]。
每个节点的值都是 0。

解法1——标记状态+贪心

从下到上dfs,标记各个节点的节点。必须使用时就使用一个监控。

class Solution {int ans = 0;public int minCameraCover(TreeNode root) {if (dfs(root) == 0) ans++;return ans;}// 0没有被覆盖,1被覆盖,使用摄像头2public int dfs(TreeNode root) {if (root == null) return 1;int l = dfs(root.left), r = dfs(root.right);if (l == 0 || r == 0) {ans++;return 2;} else if (l == 2 || r == 2) return 1;return 0;}
}

解法2——动态规划

同样是后序dfs。
状态分为:该节点上有,该节点父节点上有,该节点子节点上有。
dp 中的数值 表示 花费。

class Solution {public int minCameraCover(TreeNode root) {int[] res = dfs(root);return Math.min(res[0], res[2]);}// 该节点上有,该节点父节点上有,该节点子节点上有public int[] dfs(TreeNode root) {if (root == null) {return new int[]{Integer.MAX_VALUE / 2, 0, 0};}int[] l = dfs(root.left), r = dfs(root.right);int choose = Math.min(l[0], l[1]) + Math.min(r[0], r[1]) + 1;   // 自己选int byFa = Math.min(l[0], l[2]) + Math.min(r[0], r[2]);         // 自己不选,用他爹的int byChildren = Math.min(Math.min(l[0] + r[2], l[2] + r[0]), l[0] + r[0]);	// 自己不选,用它儿子的return new int[]{choose, byFa, byChildren};}
}

相关练习题目

P2458 [SDOI2006] 保安站岗⭐(有多个儿子节点)🚹

https://www.luogu.com.cn/problem/P2458

在这里插入图片描述
在这里插入图片描述

将节点分成三类:1.靠自己 2.靠父节点 3.靠子节点。

import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt(), root = 0;int[] cost = new int[n + 1];List<Integer>[] g = new ArrayList[n + 1];Arrays.setAll(g, e -> new ArrayList<>());for (int i = 2; i <= n + 1; ++i) {int x = scanner.nextInt(), c = scanner.nextInt(), m = scanner.nextInt();if (root == 0) root = x;    // 记录根节点标号cost[x] = c;for (int j = 0; j < m; ++j) {int y = scanner.nextInt();g[x].add(y);}}int[] res = dfs(root, g, cost);System.out.println(Math.min(res[0], res[2]));}// 自己,父节点,儿子public static int[] dfs(int x, List<Integer>[] g, int[] cost) {int c = cost[x], fa = 0, ch = Integer.MAX_VALUE;for (int y: g[x]) {int[] res = dfs(y, g, cost);c += Math.min(res[0], res[1]);      // 靠自己:从靠自己和靠爹的转移过来fa += Math.min(res[0], res[2]);     // 靠爹:从靠自己和靠儿子的转移过来ch = Math.min(ch, res[0] - res[2]); // 靠儿子:子节点不可能靠爹,且至少有一个靠自己.这里处理最少一个靠自己,最后再加上fa}return new int[]{c, fa, fa + Math.max(0, ch)};}
}

主要考虑递推公式的写法。
其中靠儿子的转移:子节点不可能靠爹,且至少有一个靠自己。先去掉这个“至少有一个靠自己”的限制条件,那么 ch 的计算就和 fa 的计算一样了。除此之外,我们要记录 res[0] - res[2] 的最小值,这样最后将其和 0 取最大值,就可以达到将至少一个靠儿子的节点修改成靠自己的节点了。

LCP 34. 二叉树染色⭐(每个节点 单独dp[k + 1]数组)

https://leetcode.cn/problems/er-cha-shu-ran-se-UGC/description/

在这里插入图片描述
提示:
1 <= k <= 10
1 <= val <= 10000
1 <= 结点数量 <= 10000

参考题解:https://leetcode.cn/problems/er-cha-shu-ran-se-UGC/solutions/1427646/by-codesheng-n-ewdf/

后序遍历。

对于每个节点,都有一个 dp[k + 1] 的数组,其中dp[i]表示到该节点连续有i个时的最大价值。

class Solution {public int maxValue(TreeNode root, int k) {return dfs(root, k)[k];}public int[] dfs(TreeNode root, int k) {if (root == null) return new int[k + 1];int[] dp = new int[k + 1];int[] l = dfs(root.left, k), r = dfs(root.right, k);// dp数组初始化dp[0] = l[k] + r[k];    // 当前节点不选// 枚举与当前节点连续的节点数量for (int i = 1; i <= k; ++i) {dp[i] = dp[i - 1];// 枚举左右子树的分配情况for (int j = 0; j < i; ++j) {dp[i] = Math.max(dp[i], l[j] + r[i - j - 1] + root.val);}}return dp;}
}

LCP 64. 二叉树灯饰⭐⭐⭐⭐⭐

https://leetcode.cn/problems/U7WvvU/description/

在这里插入图片描述
提示:
1 <= 节点个数 <= 10^5
0 <= Node.val <= 1

https://leetcode.cn/problems/U7WvvU/solutions/1846995/shu-xing-dp-by-endlesscheng-isuo/
在这里插入图片描述

代码按照记忆化搜索来写。Java要用TreeNode当数组下标可以通过Map来实现。

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode(int x) { val = x; }* }*/
class Solution {Map<TreeNode, int[][]> map;public int closeLampInTree(TreeNode root) {map = new HashMap<>();// 当前节点,祖先节点开关2的奇偶性,父节点是否切换了开关3return dfs(root, false, false);}public int dfs(TreeNode node, boolean s2, boolean s3) {if (node == null) return 0;int x = s2? 1: 0, y = s3? 1: 0;int[][] val = new int[2][2];if (map.containsKey(node)) {val = map.get(node);if (val[x][y] > 0) return val[x][y];} else {map.put(node, val);}if ((node.val == 1) == (s2 == s3)) {// 需要从开灯变成关灯状态int res1 = dfs(node.left, s2, false) + dfs(node.right, s2, false)+ 1;int res2 = dfs(node.left, !s2, false) + dfs(node.right, !s2, false) + 1;int res3 = dfs(node.left, s2, true) + dfs(node.right, s2, true) + 1;int res4 = dfs(node.left, !s2, true) + dfs(node.right, !s2, true) + 3;val[x][y] = min(res1, res2, res3, res4);} else {// 需要保持关灯状态int res1 = dfs(node.left, s2, false) + dfs(node.right, s2, false);int res2 = dfs(node.left, !s2, false) + dfs(node.right, !s2, false) + 2;int res3 = dfs(node.left, s2, true) + dfs(node.right, s2, true) + 2;int res4 = dfs(node.left, !s2, true) + dfs(node.right, !s2, true) + 2;val[x][y] = min(res1, res2, res3, res4);}return val[x][y];}public int min(int a, int b, int c, int d) {if (b < a) a = b;if (c < a) a = c;if (d < a) a = d;return a;}
}

代码耗时 672 ms。

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

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

相关文章

【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…

蓝桥杯单片机综合练习——工厂灯光控制

一、题目 二、代码 #include <reg52.h>sfr AUXR 0x8e; //定义辅助寄存器sbit S5 P3^2; //定义S5按键引脚 sbit S4 P3^3; //定义S4按键引脚unsigned char led_stat 0xff; //定义LED当前状态 unsigned char count 0; //定义50ms定时中断累…

C# Winform围棋棋盘

C# Winform简单的围棋棋盘vs2008winform小游戏C#vs2010winform棋盘C#窗体小游戏 这是一个简单的围棋棋盘小游戏&#xff0c;使用C# Winform编写棋盘界面&#xff0c;玩家可以在空白的交叉点上下棋子 项目获取&#xff1a; 项目获取&#xff1a;typora: typora/img (gitee.co…

微机原理练习题_13

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。&#xff09; 1、十六进制数5BF.C8转换成二进制数是(&#xff09; A. 11011100111111101B B. 010111011011.01101B C. 010110111111.11001B D. 010111011011.11001B 2,最适合…

全新酷盒9.0源码:多功能工具箱软件的最新iapp解决方案

全能工具箱软件酷盒&#xff1a;源码提供iapp解决方案&#xff0c;自定义打造个性化体验 酷盒是一款功能丰富的工具箱软件&#xff0c;内置众多实用功能&#xff0c;并实时更新热门功能。该软件还拥有丰富的资源库&#xff0c;用户可以在线畅玩游戏、免费下载音乐等。 我们提…

NSS [鹤城杯 2021]Middle magic

NSS [鹤城杯 2021]Middle magic 源码直接给了。 粗略一看&#xff0c;一共三个关卡 先看第一关&#xff1a; if(isset($_GET[aaa]) && strlen($_GET[aaa]) < 20){$aaa preg_replace(/^(.*)level(.*)$/, ${1}<!-- filtered -->${2}, $_GET[aaa]);if(preg_m…

【NI-DAQmx入门】频率测量

1.频率概述 时域表示给出了信号在采样时刻的幅度。 频率是指循环或周期事件的复现率&#xff0c;对于模拟或数字波形&#xff0c;信号周期的倒数就是频率。快速傅立叶变换 (FFT) 提供了一种检查频域关系的方法。傅里叶定理指出&#xff0c;时域中的任何波形都可以用正弦和余弦的…

2023.11.17使用flask将多个图片文件上传至服务器

2023.11.17使用flask将多个图片文件上传至服务器 实现功能&#xff1a; 1、同时上传多个图片文件 2、验证文件扩展名 3、显示上传文件的文件名 4、显示文件上传结果 程序结构 main.py from flask import Flask, request, jsonify, render_template import osapp Flask(__n…

6 Redis的慢查询配置原理

1、redis的命令执行流程 redis的慢查询只针对步骤3 默认情况下&#xff0c;慢查询的阈值是10ms

node实战——koa实现文件上传

文章目录 ⭐前言⭐koa实现文件上传⭐foxapi测试⭐总结⭐结束⭐前言 大家好,我是yma16,本文分享关于node实战——node实战——koa实现文件上传。 本文适用对象:前端初学者转node方向,在校大学生,即将毕业的同学,计算机爱好者。 node系列往期文章 node_windows环境变量配置…

【Python进阶】近200页md文档14大体系知识点,第4篇:linux命令和vim使用

本文从14大模块展示了python高级用的应用。分别有Linux命令&#xff0c;多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 全套Python进阶笔记地址…

ICCV2023 Tracking paper汇总(二)(多目标跟随、单目标跟随等)

十六、Integrating Boxes and Masks: A Multi-Object Framework for Unified Visual Tracking and Segmentation paper&#xff1a; https://openaccess.thecvf.com/content/ICCV2023/papers/Xu_Integrating_Boxes_and_Masks_A_Multi-Object_Framework_for_Unified_Visual_ICC…