【动态规划】【树形dp】【C++算法】968监控二叉树

作者推荐

【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数

本文涉及知识点

动态规划汇总

LeetCode:968监控二叉树

给定一个二叉树,我们在树的节点上安装摄像头。
节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。
计算监控树的所有节点所需的最小摄像头数量。
示例 1:
输入:[0,0,null,0,0]
输出:1
解释:如图所示,一台摄像头足以监控所有节点。
示例 2:
输入:[0,0,null,0,null,0,null,null,0]
输出:2
解释:需要至少两个摄像头来监视树的所有节点。 上图显示了摄像头放置的有效位置之一。
提示:
给定树的节点数的范围是 [1, 1000]。
每个节点的值都是 0。

动态规划

动态规划的状态表示

Rec(root)返回int i1,i2,i3,表示后面三种情况需要的最少摄像头。 i1,表示此子树根节点有摄像头,且子树所有节点都被监控。i2,此子树根节没有摄像头,所有节点都被监控。i3,此子树根节点无摄像头,根节点无监控,除根节点外都被监控。

动态规划的转移方程

叶子节点见初始值,本部分只讨论,非叶子节点:
i3 = min(lefti2)+min(righti2)
i2 ,左节点i1,右节点i1或i2 。或右节点i1,左节点i1,i2不存在。如果右节点不存在,则左节点i1。如果左节点不存在,则右节点i1。
i1 1 + min(lefti1,lefti2,lefti3)+min(righti1,righti2,righti3)
如果当前节点增加摄像头,则左右子树,无轮是否存在,i1,i2,i3 全部是i1。
如果当前节点没摄像头
a,一个子树i1,另外一个子树i1,i2或不存在,都是i2。
b,一个字树i1,另外一个字树i3不合法。
c,没有子树i1。两者都i2。就是i3。

动态规划的初始值

叶子节点i1,i2,i3分别为:1, 1000,0 。 1000或更大的数,表示这种可能不存在。

动态规划的填表顺序

树的先序遍历

动态规划的返回值

root的i1。

代码

核心代码

class Solution {
public:
	int minCameraCover(TreeNode* root) {		
		const auto [i1,i2,i3] =  Rec(root);
		return max(1, min(i1, i2));
	}
	std::tuple<int, int,int> Rec(TreeNode* root)
	{
		if ((nullptr == root->left) && (nullptr == root->right))
		{
			return std::make_tuple(1, 1000, 0);
		}
		int i3 = 0;
		int i21 = 1000,i22=1000;
		int i1 = 1;//	
		int iLeftMin = -1, iRightMin = -1;
		if (nullptr != root->left)
		{
			auto [t1, t2,t3] = Rec(root->left);
			iLeftMin = min(t1, t2);
			i3 += t2;
			i21 = t1;
			i1 += min(t1, min(t2, t3));
		}
		if (nullptr != root->right)
		{
			auto [t1, t2, t3] = Rec(root->right);
			iRightMin = min(t1, t2);
			i3 += t2;
			i22 = t1;
			i1 += min(t1,min(t2, t3));
		}	
		if (nullptr != root->left)
		{	
			i22 += iLeftMin;
		}
		if (nullptr != root->right)
		{			
			i21 += iRightMin;
		}
		const int i2 = min(i21, i22);
		//assert((i1 >= i3) && (i2 >= i3 ));
		std::cout << "val: " << root->val << " i1: " << i1 << " i2:" << i2 << " i3: " << i3 << std::endl;
		return std::make_tuple(i1, i2,i3);
	}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{	
	int x,  target;
	const int null = 10000;
	{
		vector<int> nodes = { 1, null, 3, null, 5, null, 7, null, 9, 10, 11, null, null, 14, 15 };
		auto root = NTree::Init(nodes);
		Solution sln;
		auto res = sln.minCameraCover(root);
		Assert(res, 3);
	}
	{
		vector<int> nodes = { 1, 2, null, 4, null, 6, null, null, 9 };
		auto root = NTree::Init(nodes);
		Solution sln;
		auto res = sln.minCameraCover(root);
		Assert(res, 2);
	}
	{
		vector<int> nodes = { 1, 2, null, 3, 4 };
		auto root = NTree::Init(nodes);
		Solution sln;
		auto res = sln.minCameraCover(root);
		Assert(res, 1);
	}
	
	
}

优化

空节点为边界条件,更简洁。

class Solution {
public:
	int minCameraCover(TreeNode* root) {		
		const auto [i1,i2,i3] =  Rec(root);
		return max(1, min(i1, i2));
	}
	std::tuple<int, int,int> Rec(TreeNode* root)
	{
		if (nullptr == root )
		{
			return std::make_tuple(1000,0,0);
		}
		auto [l1,l2,l3] = Rec(root->left);
		auto [r1, r2, r3] = Rec(root->right);
		int i1 = 1 + min(min(l1,l2),l3) + min(min(r1, r2), r3);
		int i2 = min(l1 + r2, r1 + l2);
		i2 = min(i2, l1 + r1);
		int i3 = l2 + r2;
		return std::make_tuple(i1, i2,i3);
	}
};

2023年1月版

struct CStatus
{
int m_iFillAndRootHas;// 覆盖所有节点且根节点有监控
int m_iFill;// 覆盖所有节点,根节点不一定有监控
int m_iFillChild;//覆盖子节点,不一定覆盖根节点
};
class Solution {
public:
int minCameraCover(TreeNode* root) {
CStatus stuatu = dfs(root);
return stuatu.m_iFill;
}
CStatus dfs(TreeNode* root)
{
if (nullptr == root)
{
return{ INT_MAX / 2, 0, 0 };
}
CStatus left = dfs(root->left);
CStatus right = dfs(root->right);
CStatus ret;
ret.m_iFillAndRootHas = 1 + left.m_iFillChild + right.m_iFillChild;
ret.m_iFill = min(ret.m_iFillAndRootHas, min(left.m_iFillAndRootHas+right.m_iFill,right.m_iFillAndRootHas+left.m_iFill));
ret.m_iFillChild = min(ret.m_iFillAndRootHas,left.m_iFill + right.m_iFill);
std::cout << ret.m_iFillAndRootHas << " " << ret.m_iFill << " " << ret.m_iFillChild << std::endl;
return ret;
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

16.docker删除redis缓存数据、redis常用基本命令

1.进入redis容器内部 &#xff08;1&#xff09;筛选过滤出redis容器 docker ps | grep "redis"&#xff08;2&#xff09;进入redis容器 #说明&#xff1a;d24为redis容器iddocker exec -it d24 /bin/bash2.登陆redis (1) 进入redis命令行界面 redis-cli说明&a…

elastic-job VS xxl-job

1、Elastic-job介绍 Elastic-job 是由当当网基于quartz 二次开发之后的分布式调度解决方案 &#xff0c; 由两个相对独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成 。Elastic-Job-Lite定位为轻量级无中心化解决方案&#xff0c;使用jar包的形式提供分布式任务的协调服务…

day20网页基本标签

网页基本标签 标题标签段落标签换行标签水平线标签字体样式标签注释和特殊符号 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>网页基本标签</title> </head> <body> <!--标题…

matlab使用jdbc连接数据库

1、打包jdbc 2、在matlab安装目录下&#xff0c;进去toolbox目录下&#xff0c;新建一个对应放jdbc包的文件夹&#xff0c;加入放入的是mysql的jdbc驱动包&#xff0c;就新建一个mysql目录&#xff0c;将驱动包放入mysql目录下 3、在toolbox目录下&#xff0c;找到local目录&a…

DVI接口主机连接VGA显示器解决方案:DVI转VGA转换器DV

DVI转VGA转换器概述 DVI转VGA转换器能够将DVI数字信号转换成VGA模拟信号&#xff0c;通过VGA线缆传输给VGA显示设备使用&#xff0c;这样就能实现DVI接口主机连接VGA接口的显示器。 DVI转VGA转换器DV DVI转VGA转换器DV接口说明 DVI转VGA转换器DV接口介绍 DVI转VGA转换器连接示…

对象内存与方法调用机制

对象的内存布局 对象、字符串和数组都是引用类型&#xff0c;指向的数 我们以下面main方法部分代码片段为例&#xff1a; Cat cat new Cat(); cat.name "小白"; cat.age 12; cat.color "白色"; 首先执行mian方法&#xff0c;会在栈里创建一个独立的m…

PMP资料怎么学?PMP备考经验分享

PMP考试前大家大多都是提前备考个一两个月&#xff0c;但是有些朋友喜欢“不走寻常路”&#xff0c;并不打算去考PMP认证&#xff0c;想要单纯了解PMP&#xff0c;不管要不要考证&#xff0c;即使是仅仅学习了解一下我个人都非常支持&#xff0c;因为专业的基础的确能提高工作效…

基恩士 KV-8000 PLC通讯简单测试

1、KV-8000通讯协议 基恩士 KV-8000 PLC支持多种通讯方式&#xff0c;包括&#xff1a;OPC UA、Modbus、上位链路命令等。其中OPC UA需要对服务器和全局变量进行设置&#xff0c;Modbus需要调用功能块。默认支持的是上位链路命令&#xff0c;实际是一条条以回车换行结束的ASCII…

掌握核心:二进制运算与多进制数相互转换

常用进制数 十进制&#xff08;D&#xff09; 十进制是人们日常生活用的最多也最熟悉的一种进位计数制&#xff0c;由0、1、2、3、4、5、6、7、8、9这十个数码组成&#xff0c;基数为10。 十进制的特点是&#xff1a;逢十进一&#xff0c;借一当十 二进制&#xff08;B) 二…

【Crypto | CTF】BUUCTF 萌萌哒的八戒

天命&#xff1a;这年头连猪都有密码&#xff0c;真是奇葩&#xff0c;怪不得我一点头绪都没有 拿到软件&#xff0c;发现是.zip的压缩包&#xff0c;打不开&#xff0c;改成7z后缀名&#xff0c;打开了 发现是一张图片 也只有下面这行东西是感觉是密码了&#xff0c;又不可能…

GPT原始论文:Improving Language Understanding by Generative Pre-Training论文翻译

1 摘要 自然语理解包括文本蕴含、问题回答、语义相似性评估和文档分类等一系列多样化的任务。尽管大量未标注的文本语料库很丰富&#xff0c;但用于学习这些特定任务的标注数据却很稀缺&#xff0c;这使得基于区分性训练的模型难以充分发挥作用。我们展示了通过在多样化的未标…

Java split 分割字符串避坑

使用split进行字符串分割时需要注意2点 1、特殊字符作为分隔符时需要使用\\进行转义(如\\ -> \\\\; | -> \\| ) 特殊字符 .$|()[{^?*\\ 例如对"|"分隔 未转义 String str "01|02|03"; String[] strArr str.split("|");System.out.…

前端登陆加密解决方案

项目背景 环食药烟草的数据下载模块中&#xff0c;需要判断用户在进行数据下载时是进行了登录操作&#xff0c;如果没有登录要跳转登陆页面&#xff0c;输入账号和密码进行登录。 使用场景 项目中需要前端书写登录页面&#xff0c;用户输入账号密码&#xff0c;前端获取到用…

leetcode 3.无重复字符的最长字串(滑动窗口) (C++)DAY2

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 示例 1: 输入: s “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”&#xff0c;所以其长度为 3。 示…

ChatGPT Plus如何升级?信用卡付款失败怎么办?如何使用信用卡升级 ChatGPT Plus?

ChatGPT Plus是OpenAI提供的一种高级服务&#xff0c;它相较于标准版本&#xff0c;提供了更快的响应速度、更强大的功能&#xff0c;并且用户可以优先体验到新推出的功能。 尽管许多用户愿意支付 20 美元的月费来订阅 GPT-4&#xff0c;但在实际支付过程中&#xff0c;特别是…

mac如何实现升级node版本、切换node版本

一、 查看node所有版本&#xff08;前提:安装了nodejs&#xff09; npm view node versions二、安装指定node版本 sudo n 版本号三、检查目前安装了哪些版本的node&#xff0c;会出现已安装的node版本 n四、切换已安装的node版本 sudo n 版本号其他命令 1、sudo npm cache…

154基于matlab的二维元胞自动机模拟森林火灾(生命游戏 )和模拟收费站交通流

基于matlab的二维元胞自动机模拟森林火灾&#xff08;生命游戏 &#xff09;和模拟收费站交通流。全国大学生美国建模竞赛&#xff0c;程序已调通&#xff0c;可直接运行。 154 元细胞自动机 森林起火 收费站交通 (xiaohongshu.com)

基于微信小程序的医保行政执法案件管理系统

本系统设计的是一个医保行政执法的网站&#xff0c;此网站使用户实现了不需出门就可以在手机或电脑前进行网上查询需求信息等。 用户在注册登陆后&#xff0c;在客户端可以实现&#xff1b;案件信息、结案归档、我的等。然而管理员则可以在服务端直接管理&#xff1b;个人中心、…

Linux校准时间 Centos

Linux校准时间 Centos 首先&#xff0c;确保系统中已经安装了tzdata包。如果没有安装&#xff0c;可以使用以下命令安装&#xff1a; sudo yum install tzdata设置系统时区为上海&#xff1a; sudo timedatectl set-timezone Asia/Shanghai验证时区设置是否生效&#xff1a;…

Android studio打开md无法显示md渲染问题

Where is Android Studio Markdown support plugin preview preference? - Stack Overflow android studio开发无法选择markdown渲染功能的问题 原因是java runtime出了问题 搜索下面功能 Choose Boot Java Runtime for the IDE 选择带JCEF的 可以选最新的java版本 重启之…