洛谷 P1873 砍树 (二分 简单)

【二分答案】是分治的一种,这类问题很经典,接下来几篇文章会关于二分答案相关的文章,希望同学们可以完成10道以上的【二分答案】相关问题,以此来加深对【二分答案】这类问题的个人理解。
原公众号链接:分治第二讲:二分答案之砍树问题

一、题目

题目链接:

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

题意:找到一个最恰当的高度砍树,使得砍树得到的树木高度之和刚好大于等于M即可。看题目数据范围,1<=n<=10^6,通过这个数据范围,可以反推出你的算法时间复杂度只能是低于O(nlogn),因此瞬间想到二分,往二分上靠拢。

二、题目分析

题意很简单,如何求解呢?其实会发现,直接求解不是很容易求解,该问题可以归纳总结为【最小值最大问题】,即需要求解的砍树高度,在满足题目要求的情况下要最大。【最小值最大】和【最大值最小】问题均可以通过【二分答案】思路完成,在完成【二分】之前,我们先用暴力实现,然后再修改为二分即可。

对于任何一个问题,一般有两种方式解决,一种是直接求解,另一种是检验,检验指的是给一个可能解,带入题目中检查该解是否满足题目,检验类似于数学中的选择题,如果不会直接求解,那么可以依次把四个选项带入题目中检验验证即可;我个人认为:检验的难度小于直接求解。

该题目求解最恰当的砍树高度h,假设最高的那棵树的高度为maxH, 则h的取值范围为[0, maxH];可以依次让k从maxH开始依次递减直到0,递减过程中,如果某个取值恰当满足砍的树的高度之和大于等于M,则当前k就是最终解,直接输出并结束程序即可。

三、题目解决

上一部分分析了题目的求解方法并可以通过暴力的方法依次从maxH到0遍历,找到第一个满足题目要求的高度即可,试想一个问题,如果某个高度hi砍树不能满足砍掉的树的高度和大于等于M,那么对于大于等于hi的高度hj来说也无法满足题意,理解了上面这个特性就可以通过二分来快速求解高度h了。

二分的左边界left为0,右边界right为maxH,在这里扩展一个点,如果根据题意不好确定二分的初始边界left和right,那么可以直接暴力将left初始化为0,right初始化为一个很大的值,比如1e8;

Step1:取二分的中间值mid = left + (right-left)/2,检查以mid为砍树高度,是否可以得到高度大于等于M的树木;

Step2:如果不行,那么大于等于mid的高度均无法得到,因此缩小二分区间,right = mid-1;

Step3:如果可以,那么mid就是可能的一个解,保存在ans中,缩小二分区间,left = mid+1; (一定要记住,使用二分,禁止出现left = mid,因为这样很有可能陷入死循环,所以务必要避免left = mid,但是可以有right = mid);

二分问题解决了,如何实现检验函数check呢?也很简单,给你一个高度mid,遍历所有树木的高度,用sum记录砍掉的树的高度和,则如果当前树的高度小于mid,则没有得到树木,否则,在当前树上可以砍下树的高度减掉mid的差值的高度的树木,最终只需要判断sum是否大于M即可。

四、code编码

暴力代码O(n^2)


#include "iostream"
using namespace std;
const int M = 1000010;
int n, m, a[M], l = 0, r = -1, ans = -1;// check函数的功能是:给一个高度x,返回该高度是否可以砍出高度和为m的树木,如果可以返回true,否则返回false
bool check(int x) {long long sum = 0;for(int i=1; i<=n; i++) {  // 遍历所有树木sum += max(0, a[i]-x);  // 求解x的高度,每个树可以砍多少树木}return sum >= m;   // 砍出的总和是否大于m,如果大于m则返回true,否则返回false;
} int main() {cin >> n >> m;for(int i=1; i<=n; i++) {cin >> a[i];r = max(r, a[i]);  // 确定右边界,为最高的树的高度}for(int x = r; x>=l; x--) {if(check(x)) {  cout << x << endl;return 0;}}}

暴力超时6个点,AC了4个点,因此通过二分优化如下:

二分代码O(nlogn)


#include "iostream"
using namespace std;
const int M = 1000010;
int n, m, a[M], l = 0, r = -1, ans = -1;// check函数的功能是:给一个高度x,返回该高度是否可以砍出高度和为m的树木,如果可以返回true,否则返回false
bool check(int x) {long long sum = 0;for(int i=1; i<=n; i++) {  // 遍历所有树木sum += max(0, a[i]-x);  // 求解x的高度,每个树可以砍多少树木}return sum >= m;   // 砍出的总和是否大于m,如果大于m则返回true,否则返回false;
} int main() {cin >> n >> m;for(int i=1; i<=n; i++) {cin >> a[i];r = max(r, a[i]);  // 确定右边界,为最高的树的高度}while(l <= r) {  // 二分答案int mid = l + (r-l)/2;  // 找出区间的中间值if(check(mid)) {  // 如果当前mid高度可以砍出m的树木高度,则说明mid是一个可能解,保存并缩小区间ans = mid;  // 保存可能解l = mid + 1; // 缩小区间} else {r = mid-1;  // mid高度不行,因此需要缩小右边界,答案在左区间}}cout << ans;}

二分细节是魔鬼呀,琢磨什么时候是while(left<right),什么时候是while(left <= right)?

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

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

相关文章

学点心理学做一个灵魂有趣的人,为你讲解生动好玩的心理学话题

一、教程描述 催眠真的能重返前生&#xff1f;星座为什么那么准&#xff1f;如何”洗脑”&#xff1f;为什么学了那么多教养课程&#xff0c;还是养不好自己的孩子&#xff1f;心理问题可以通过自学心理学自救吗&#xff1f;靠谱的心理咨询师长啥样&#xff1f;本套教程用风趣…

Android 项目工程配置签名文件

1. Android签名证书(.keystore) Android平台打包发布apk应用&#xff0c;需要使用数字证书&#xff08;.keystore文件&#xff09;进行签名&#xff0c;用于表明开发者身份。   Android证书的生成是自助和免费的&#xff0c;不需要审批或付费。   可以使用JRE环境中的keyto…

ShardingSphere-JDBC初探

引言 为什么使用分库分表&#xff1f; 数据量太大单表放不下&#xff0c;并且公司不希望切换产品&#xff0c;可选的方案不多&#xff0c;ShardingSphere就是不错的选择。 切换产品指的是换成es、clickhouse、hbase这种支持大数据&#xff0c;试想一下切换产品对整个项目的改…

简易2048游戏的实现(C++)

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼《定风波莫听穿林打叶声》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#xff09; 目录 一、效果图二、代码&#xff08;带注释&#xff09;三、说明 一、效果图 二、代码&#xff08;带…

【计算机网络实验】educoder实验八 IPV6网络及其路由 头歌

第一关 IPV6网络基础 //千万不要破坏文档原有结构与内容&#xff01;&#xff01;&#xff01; //以下均为判断题&#xff0c;F&#xff1a;表示错误&#xff0c;T&#xff1a;表示正确 //答案必须写在相应行末尾括号内&#xff0c;F与T二选一&#xff0c;大写 // 1、ipv6协议…

国贸股份发来感谢信,甄知项目优质交付服务和专业实施方法获客户高度认可

近日&#xff0c;由甄知科技携手国有控股上市公司厦门国贸集团股份有限公司下属数科公司厦门国贸数字科技有限公司&#xff08;以下简称“国贸股份”&#xff09;打造的国贸股份“智服云”项目完成验收工作。为感谢甄知科技在项目顺利实施中所作的贡献和努力&#xff0c;国贸股…

企业培训系统开发: 技术创新引领学习革新

在现代企业管理中&#xff0c;培训成为推动员工发展和企业创新的核心。随着科技的快速发展&#xff0c;企业培训系统的开发已经成为提高培训效果、降低成本的有效途径。本文将介绍企业培训系统开发的一些关键技术和代码实例&#xff0c;展示如何通过技术创新引领学习革新。 1…

56K star!一键拥有跨平台 ChatGPT 应用:ChatGPT-Next-Web

前言 现在围绕 openai 的客户端层出不穷&#xff0c;各路开发大神可以说是各出绝招&#xff0c;我也试用过几个国内外的不同客户端。 今天我们推荐的开源项目是目前我用过最好的ChatGPT应用&#xff0c;在GitHub超过56K Star的开源项目&#xff1a;ChatGPT-Next-Web。 ChatGP…

chatgpt3.5和chatgpt4的区别

ChatGPT4是基于GPT-3模型的一个实例&#xff0c;但ChatGPT4已经进行了进一步的改进和优化。GPT-3&#xff08;第三代生成式预训练模型&#xff09;是OpenAl开发的一个大型语言模型&#xff0c;它在很多自然语言处理任务中表现出色。 ChatGPT4继承了GPT-3的基本架构和能力&…

在 Walrus 上轻松集成 OpenTofu

OpenTofu 是什么&#xff1f; OpenTofu 是一个开源的基础设施即代码&#xff08;IaC&#xff09;框架&#xff0c;被提出作为 Terraform 的替代方案&#xff0c;并由 Linux 基金会管理。OpenTofu 的问世为应对 HashiCorp 将 Terraform 的许可证从 Mozilla Public License v2.0…

ubuntu22.04配置双网卡绑定提升带宽

这里写自定义目录标题 Bonding简介配置验证参考链接 Bonding简介 bonding(绑定)是一种linux系统下的网卡绑定技术&#xff0c;可以把服务器上n个物理网卡在系统内部抽象(绑定)成一个逻辑上的网卡&#xff0c;能够提升网络吞吐量、实现网络冗余、负载均衡等功能&#xff0c;有很…

性能优化-OpenMP基础教程(五)-全面讲解OpenMP基本编程方法

本文主要介绍OpenMP编程的编程要素和实战&#xff0c;包括并行域管理详细实战、任务分担详细实战。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;C…