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

news2024/9/24 5:32:46

文章目录

  • 前期知识 & 相关链接
  • 例题
    • 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被覆盖,使用摄像头2
    public 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的奇偶性,父节点是否切换了开关3
        return 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.coloradmin.cn/o/1228336.html

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

相关文章

时间序列预测实战(十七)利用Prophet实现电力负荷长期预测(附代码+数据集+详细讲解)

一、本文介绍 Prophet是一个由Facebook开发的开源工具&#xff0c;用于时间序列预测。这个工具特别适合于具有强季节性影响和多个历史数据季节的业务时间序列数据。Prophet的主要思想是将数据分解为如下三个部分&#xff1a;趋势、季节性、节假日和特殊事件。这个模型非常适合…

GIT无效的源路径/URL

ssh-add /Users/haijunyan/.ssh/id_rsa ssh-add -K /Users/haijunyan/.ssh/id_rsa

SQL基础理论篇(七):多表关联的连接算法

文章目录 简介Nested LoopsMerge JoinHash Join总结参考文献 简介 多表之间基础的关联算法一共有三种&#xff1a; Hash JoinNested LoopsMerge Join 还有很多基于这三种基础算法的变体&#xff0c;以Nested Loops为例&#xff0c;就有用于in和exist的半连接&#xff08;Nes…

【Android Jetpack】Hilt的理解与浅析

文章目录 依赖注入DaggerHiltKoin添加依赖项Hilt常用注解的含义HiltAndroidAppAndroidEntryPointInjectModuleInstallInProvidesEntryPoint Hilt组件生命周期和作用域如何使用 Hilt 进行依赖注入 本文只是进行了简单入门&#xff0c;博客仅当做笔记用。 依赖注入 依赖注入是一…

文档向量化工具(一):Apache Tika介绍

Apache Tika是什么&#xff1f;能干什么&#xff1f; Apache Tika是一个内容分析工具包。 该工具包可以从一千多种不同的文件类型&#xff08;如PPT、XLS和PDF&#xff09;中检测并提取元数据和文本。 所有这些文件类型都可以通过同一个接口进行解析&#xff0c;这使得Tika在…

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

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

Day35力扣打卡

打卡记录 相邻字符不同的最长路径&#xff08;树状DP&#xff09; 链接 若节点也存在父节点的情况下&#xff0c;传入父节点参数&#xff0c;若是遍历到父节点&#xff0c;直接循环里 continue。 class Solution:def longestPath(self, parent: List[int], s: str) -> in…

《微信小程序开发从入门到实战》学习二十

3.3 开发创建投票页面 3.3.8 使用icon图标文件 原来已经实现了投票选项的增加和修改功能&#xff0c;现在还差删除。现在为每一个选项增加删除按钮&#xff0c;可以以通过icon图标组件实现。 icon常用属性如下&#xff1a; type icon的类型&#xff0c;有success、s…

Linux虚拟机中网络连接的三种方式

Linux 虚拟机中网络连接的三种方式 先假设一个场景&#xff0c;在教室中有三个人&#xff1a;张三、李四和王五&#xff08;这三个人每人有一台主机&#xff09;&#xff0c;他们三个同处于一个网段中&#xff08;192.169.0.XX&#xff09;&#xff0c;也就是说他们三个之间可…

ICASSP2023年SPGC多语言AD检测的论文总结

文章目录 引言正文AbstractRelated ArticleNo.1: CONSEN: COMPLEMENTARY AND SIMULTANEOUS ENSEMBLE FOR ALZHEIMERSDISEASE DETECTION AND MMSE SCORE PREDICTION特征相关模型结构数据处理结果分析 No.2: CROSS-LINGUAL TRANSFER LEARNING FOR ALZHEIMERS DETECTION FROM SPON…

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…

开源与闭源:大模型发展的双重走向

目录 前言开源和闭源的优劣势比较开源的优势闭源的优势 开源和闭源对大模型技术发展的影响对技术发展的影响对数据共享的影响对业务拓展的影响 开源与闭源的商业模式比较开源的商业模式闭源的商业模式 处在大模型洪流中&#xff0c;向何处去&#xff1f;结语 前言 随着人工智能…

【Flink】核心概念:任务槽(Task Slots)

任务槽 每个 worker&#xff08;TaskManager&#xff09;都是一个 JVM 进程&#xff0c;可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task&#xff0c;就有了所谓的 task slots&#xff08;至少一个&#xff09;。 每个任务槽&#xf…

H110主板搭配魔改QNCW升级小记

最近搬家完毕&#xff0c;翻出来一块闲置已久的qncw&#xff0c;隐约记得是买的主板套装&#xff0c;现在主板早已不知踪影&#xff0c;剩下孤零零一个CPU&#xff0c;一起翻出来一个G3900T亮机CPU&#xff0c;应该是同时代的产物。 qncw百度上一搜&#xff0c;发现参数还行&am…

CICD 持续集成与持续交付——jenkins

部署 软件下载&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/ [rootcicd2 ~]# rpm -ivh jdk-11.0.15_linux-x64_bin.rpm[rootcicd2 ~]# yum install -y fontconfig[rootcicd2 ~]# rpm -ivh jenkins-2.432-1.1.noarch.rpm启动服务 [rootcicd2 ~]# systemctl…

【Java】网络编程基础—InetAddress类和URL编程

&#x1f33a;个人主页&#xff1a;Dawn黎明开始 &#x1f380;系列专栏&#xff1a;Java ⭐每日一句&#xff1a;为了那个远方&#xff0c;你要奋不顾身 &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️ 文章目录 一.&#x…

Python编程技巧 – 使用字符串(Strings)

Python编程技巧 – 使用字符串&#xff08;Strings) Python Programming Essentials – Using Strings 本文简要介绍如何使用字符串&#xff0c;来进行Python编程。字符串有很多用途&#xff0c;包括输出结果、反馈状态、数据处理以及切片和文本筛选等 1. 字符串 字符串(St…

DevToys:开发者的多功能瑞士军刀,让编程更高效!

DevToys&#xff1a;开发者的多功能瑞士军刀&#xff0c;让编程更高效&#xff01; DevToys 是一款专为开发者设计的实用工具&#xff0c;它能够帮助用户完成日常的开发任务&#xff0c;如格式化 JSON、比较文本和测试正则表达式&#xff08;RegExp&#xff09;。它的优势在于…

开源WIFI继电器之硬件电路

一、原理图 源文件 二、原理图说明 1、器件说明 U4&#xff1a;ESP8285模块 U6&#xff1a;触发器 U3&#xff1a;继电器 2、继电器状态检测说明 检测继电器线圈是否通电来判断继电器是否导通&#xff0c;当Q1不导通时&#xff0c;Q1集电极的电压为3.3V&#xff0c;经…

微机原理练习题_13

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