[Daimayuan] 树(C++,动态规划,01背包方案数)
有一棵 n n n 个节点的以 1 1 1 号点为根的有根树。现在可以对这棵树进行若干次操作,每一次操作可以选择树上的一个点然后删掉连接这个点和它的儿子的所有边。
现在我们想知道对于每一个 k k k ( 1 ≤ k ≤ n 1≤k≤n 1≤k≤n),最少需要多少次操作能让图中恰好存在 k k k 个联通块。
输入格式
第一行输入一个正整数 n n n。
第二行输入 n − 1 n−1 n−1 个整数 f 1 , f 2 , . . . , f n − 1 f_1,f_2,...,f_{n−1} f1,f2,...,fn−1, f i f_i fi 表示 i + 1 i+1 i+1 号点的父亲,保证 1 ≤ f i ≤ i 1≤f_i≤i 1≤fi≤i。
输出格式
输出 n n n 个整数,第 i i i 个数表示 k = i k=i k=i 时的答案,如果无法让图中恰好存在 i i i 个联通块,则输出 -1
。
样例输入1
6
1 2 1 1 2
样例输出1
0 -1 1 1 -1 2
数据规模
共 10 10 10 个测试点。
测试点 1 , 2 , 3 1,2,3 1,2,3 满足 n ≤ 20 n≤20 n≤20。
测试点 4 , 5 , 6 4,5,6 4,5,6 满足 n ≤ 100 n≤100 n≤100。
对于所有数据,满足 1 ≤ n ≤ 3000 1≤n≤3000 1≤n≤3000。
解题思路
对于一棵树来说,删去任意一条边都会使连通块数目 + 1 +1 +1。
那么要判断能否得到 k k k个连通块,我们只需要判断能否恰好删去 k − 1 k-1 k−1条边。
题目要求操作为:删除一个节点与子节点之间的所有边。
那么统计每个节点的子节点数目,然后就变为了01背包可行性问题:
每一个节点都是一个物品,问能否恰好装满容量为 k − 1 k-1 k−1的背包?
for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = 0; j < n; j++) {//尝试新的重量组合if (j - items[i] >= 0)ans[i][j] = ans[i - 1][j] || ans[i - 1][j - items[i]];elseans[i][j] = ans[i - 1][j];}
}
以上我们只是检验了可行性问题,但是题目中还有另外一个要求:操作次数最少。
因为在物品组合中没有先后顺序,所以我们可以通过物品组合中的物品数量来确定操作次数。
只有新的操作次数小于旧的操作次数的时候,我们才进行更新。
for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = 0; j < n; j++) {//尝试新的重量组合if (j - items[i] >= 0 && ans[i - 1][j] && ans[i - 1][j - items[i]])ans[i][j] = min(ans[i - 1][j], ans[i - 1][j - items[i]] + 1);else if (ans[i - 1][j])ans[i][j] = ans[i - 1][j];else if (j - items[i] >= 0 && ans[i - 1][j - items[i]])ans[i][j] = ans[i - 1][j - items[i]];}
}
注:1)以上代码段中,ans
中元素的含义发生了变化:可行/不可行 -> 物品数量;
2)为了与不存在的组合(ans[i][j] = 0
)相区分,我们为所有存在的组合物品数量添加偏置bias
,也就是说,物品数量 = ans[i][j] - bias
。
以上代码的空间复杂度、时间复杂度均可以接受,可以AC,接下来是优化部分qwq。
因为嫌弃这个算法的空间复杂度,所以我们对其进行优化,压缩到二维数组:
for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = 0; j < n; j++) {//尝试新的重量组合if (j - items[i] >= 0 && ans[(i - 1) % 2][j] && ans[(i - 1) % 2][j - items[i]])ans[i % 2][j] = min(ans[(i - 1) % 2][j], ans[(i - 1) % 2][j - items[i]] + 1);else if (ans[(i - 1) % 2][j])ans[i % 2][j] = ans[(i - 1) % 2][j];else if (j - items[i] >= 0 && ans[(i - 1) % 2][j - items[i]])ans[i % 2][j] = ans[(i - 1) % 2][j - items[i]];}
}
还是嫌弃?继续压,压缩到一维数组:
for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = n; j >= items[i]; j--) {//尝试新的重量组合if (j - items[i] >= 0 && ans[j] && ans[j - items[i]])ans[j] = min(ans[j], ans[j - items[i]] + 1);else if (ans[j]) ans[j] = ans[j];else if (j - items[i] >= 0 && ans[j - items[i]])ans[j] = ans[j - items[i]] + 1;}
}
然后我们删除一些无用的部分:
for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = n; j >= items[i]; j--) {//尝试新的重量组合if (ans[j] && ans[j - items[i]]) ans[j] = min(ans[j], ans[j - items[i]] + 1);else if (ans[j - items[i]]) ans[j] = ans[j - items[i]] + 1;}
}
嗯,好看多了qwq。
最后,AC代码如下:
#include <iostream>
using namespace std;
const int max_n = 3000;int ans[max_n + 1], n;
int items[max_n + 1];int main() {cin >> n;int fa;for (int i = 1; i < n; i++) {cin >> fa;items[fa]++;}int bias = 1;ans[0] = bias;for (int i = 1; i <= n; i++) {//尝试每一个物品for (int j = n; j >= items[i]; j--) {//尝试新的重量组合if (ans[j] && ans[j - items[i]]) ans[j] = min(ans[j], ans[j - items[i]] + 1);else if (ans[j - items[i]]) ans[j] = ans[j - items[i]] + 1;}}cout << 0;for (int i = 2; i <= n; i++) {cout << ' ' << ans[i - 1] - bias;}return 0;
}
相关文章:

[Daimayuan] 树(C++,动态规划,01背包方案数)
有一棵 n n n 个节点的以 1 1 1 号点为根的有根树。现在可以对这棵树进行若干次操作,每一次操作可以选择树上的一个点然后删掉连接这个点和它的儿子的所有边。 现在我们想知道对于每一个 k k k ( 1 ≤ k ≤ n 1≤k≤n 1≤k≤n),最少需要多少次操作能…...

如何选择源代码加密软件
(SDC沙盒)和DLP、文档加密、云桌面等,其优缺点做客观比较如下: 比较内容安全容器(SDC沙盒)DLP文档加密云桌面代表厂家*信达卖咖啡、赛门贴科亿*通、IP噶德、*盾、*途四杰、深*服设计理念以隔离容器加准入技术为基础,构…...

TO-B类软件产品差异化
产品差异化,是在市场众多同质化产品中,突出自身产品亮点的重要方式。对于客户来讲其选择是多种多样的,与其花费大量的时间研究每一家产品的特点,还不如直接选择品牌更大、价格更低的产品来的直接,因此显而易见的突出产…...

设计模式之美-实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
领域驱动设计(Domain Driven Design,简称DDD)盛行之后,这种基于贫血模型的传统的开发模式就更加被人诟病。而基于充血模型的DDD开发模式越来越被人提倡。所以,我打算用两节课的时间,结合一个虚拟钱包系统的…...

ChatGPT如何训练自己的模型
ChatGPT是一种自然语言处理模型,它的任务是生成自然流畅的对话。如果想要训练自己的ChatGPT模型,需要进行大量的数据收集、预处理、配置训练环境、模型训练、模型评估等过程。本文将详细介绍这些过程,帮助读者了解如何训练一个高品质的ChatGP…...

springboot使用线程池的实际应用(一)
在实际Spring Boot项目中,我们可以使用Java的原生多线程或者使用Spring自带的线程池进行多线程编程。多线程的好处在于能够提高应用程序的运行效率,特别是在某些计算密集型场景下。以下是一些使用多线程的典型场景: 并发处理请求:…...

ESP-8266学习笔记
1、学习地址 【XMF09F系列资源】基于MicroPython的ESP8266物联网应用开发-赛教资源目录汇总-小蜜蜂笔记 Quick reference for the ESP8266 — MicroPython latest documentation 2、MicroPython及相关开发资源 3、固件烧录与uPyLoader的使用 烧录教程参考: https://www.…...

Java泛型简单的使用
前言 Java里面的泛型在实际开发中运用的很多,学过C的同学一定知道C的模板,而Java中的泛型,一定程度上和它还是挺像的。 相信写Java的人,大都有用过List的实现类ArrayList。在Java没有泛型之前,它的内部是一个Object的…...

深度探索:Qt CMake工程编译后的自动打包策略
深度探索:Qt CMake工程编译后的自动打包策略 1. 引言(Introduction)1.1 Qt和CMake的基本概念(Basic Concepts of Qt and CMake)1.2 自动打包的重要性(Importance of Automatic Packaging) 2. Qt…...

2.7 编译型和解释型
2.7 编译型和解释型 前面我们使用java和javac命令把Hello,World!在控制台输出。那为什么输出,这里我们需要掌握两个知识点。编译型语言和解释型语言。在计算机的高级编程语言就分为编译型语言和解释型语言。而我们的Java既有编译型的特点也有…...

校园网自动登陆(河南科技学院)
1. 介绍 河南科技学院校园网自动登陆(新乡的很多系统相似,可能也可以用?),java版。可以实现电脑,路由器,软路由的自动认证wifi,后续会上传docker版本的。 源码地址 github:https://…...

C++11 override和final关键字
C11中的override和final关键字是为了增强代码的编译时类型检查和面向对象设计中的继承机制。 override关键字用于显示地表明派生类中的成员函数覆盖了基类中的虚函数。当派生类中的函数与基类中的虚函数签名不同或者没有使用override关键字时,编译器会给出警告或错…...

kafka的log存储解析
kafka的log存储解析——topic的分区partition分段segment以及索引等 引言Kafka中的Message是以topic为基本单位组织的,不同的topic之间是相互独立的。每个topic又可以分成几个不同的partition(每个topic有几个partition是在创建topic时指定 的),每个…...

4.文件系统
组成 Linux:一切皆文件 索引节点(I-node) I-node(Index Node):文件系统的内部数据结构,用于管理文件的元数据和数据块。 文件的元数据:包括文件的权限、拥有者、大小、时间戳、索引…...

Shell脚本case in esac分支语句应用
记录:434 场景:Shell脚本case in esac分支语句应用。 版本:CentOS Linux release 7.9.2009。 1.case in esac格式 格式: case 值 in 模式1)expression;; 模式2)expression;; 模式n)expression;; esac 解析:case…...

【线性dp必学四道题】线性dp四道经典例题【最长上升子序列】、【最长公共子序列】、【最长公共上升子序列(maxv的由来)】【最长公共子串】
【最长上升子序列】、【最长公共子序列】、【最长公共上升子序列】 最长上升子序列f[i] 表示以i结尾的最长子序列 最长公共子序列f[i][j] 表示 a前i 和 b前j个 最长公共长度 最长公共上升子序列f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合 最长公共子…...

追寻幸福:探索幸福的关键特征和行为
目录 1. 积极的心态 2. 良好的人际关系 3. 自我接纳和自尊 4. 追求意义和目标 5. 健康的身心状态 6. 感知和实现个人价值 幸福是一个主观的感受,因此不同的人对于幸福的定义和追求方式可能会有所不同。然而,有一些共同的特点和行为模式,…...

Redis-02-集群
一、redis5搭建集群 1.1、案例:搭建6台redis主机,配置如下 redis并发量:https://www.gxlcms.com/redis-350423.html主机IP:192.168.168.60~65修改redis配置文件hash槽移动,槽内的数据也随之移动 [root60 ~]# vim /e…...

【2023 · CANN训练营第一季】MindSpore模型快速调优攻略 第三章——MindSpore云上调试调优
1.ModelArts云上调试调优 ModelArts密钥初始化 详细教程: 初始化OBS服务 创建训练作业 2.MindSpore IDE插件效率提升 通过智能代码块推荐、代码自动补全等特性,提升MindSpore脚本开发效率,对接ModelArts云服务,实现模型训…...

python笔记17_实例演练_二手车折旧分析p2
…… 书接上文 4.车辆等级维度 探查车龄为5年的车辆,折旧价值与车辆等级的关系。 # 筛选出车龄为5的数据创建新表 data_age5 data[data[age] 5] data_age5 # 分组聚合计算均值 data_car_level data_age5.groupby(car_level_name)[lowest_price].mean().reset…...

android 12.0长按Power弹出关机对话框去掉屏幕截图和紧急呼救功能
1.概述 在12.0的系统长按关机键,会弹出关机的对话框,关机对话框里面由关机重启截图和紧急呼叫等功能,而由于开发功能需求要求去掉屏幕截图和紧急呼叫等功能,所以就要先找到关机对框的代码 然后实现功能 功能分析: 长按电源键弹出关机对话框,通过adb shell命令发现 就是f…...

2023年下半年软考高级需要报班吗?
首先,对于软考高级考试报班与否的问题,需要根据自身的情况来做出决定。如果你有较强的自学能力,且具备丰富的实际工作经验和技术知识,那么不报班也完全可以自学备考。但如果你对软件工程的知识掌握程度较低,或者时间紧…...

使用WordPress提高企业敏捷性
喜欢WordPress的原因有很多:该平台非常适合内容管理以及控制预算。此外, 在 提高开发效率和简化项目管理方面,WordPress可以通过多种方式提供帮助。 对于任何企业业务,目标始终是在不影响质量的情况下更快地启动项目、发布修复和…...

SSM编程---Day 07
目录 SpringMVC 一、概念 二、springMVC的请求处理流程 三、mvc:annotation-driven 标签的作用 四、HandlerMapping、Handler和HandlerAdapter的介绍 五、SpringMVC 体系结构 六、SpringMVC的常用注解 七、view和controller之间的传值 SpringMVC 一、概念 1、 Spring…...

Seata术语
1.什么是Seata Seata是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 官网 2.Seata能干嘛 一个典型的分布式事务过程 分布式事务处理过程的一ID三组件模型: Transaction ID XID 全局唯一的事务ID三组…...

【Axure教程】通过文本框维护下拉列表选项
下拉列表(Dropdown List)是一种常见的用户界面元素,用于提供一组选项供用户选择。它通常以一个展开的列表形式出现,用户可以点击或选择列表中的一个选项。一般来说,他的选项值是由系统代码组成的,所以一般是…...

【C++】基础知识--输入/输出(5)
前面部分的示例程序几乎没有提供与用户的交互(如果有的话)。他们只是在屏幕上打印简单的值,但标准库提供了许多其他方式通过其输入/输出功能与用户交互。本节将简要介绍一些最有用的方法。 cin标准输入cout标准输出cerr标准错误(输…...

经典文献阅读之--PIBT(基于可见树的实时规划方案)
0. 简介 作为路径规划而言,不单单有单个机器人自主路径规划,近年来随着机器人行业的兴起,多机器人自主路径规划也越来越受到关注,对于多智能体寻路(MAPF)。一般的操作会给定一个地图、机器人集群、以及它们的初始位置和目的地&am…...

SAP-MM-计算方案字段解析
01、 “步骤”:标识此条件类型在计算方案中的顺序编号,此编号会影响到后续业务中条件类型的排序,不同条件类型之间的编号最好间隔大一些,这样设置便于以后对计算方案进行扩展; 02、 “计数器”࿱…...

go-gf框架两个表以事务方式写入示例
下面是对每一行代码的中文解释: // 创建数据库连接对象 var tx gdb.TX这行代码声明了一个名为tx的变量,类型为gdb.TX,表示数据库事务对象。 // 开启事务 if tx, err g.DB().Ctx(ctx).Begin(ctx); err nil {这行代码通过在数据库连接&…...