蓝桥杯:C++二分算法

在基本算法中,二分法的应用非常广泛,它是一种思路简单、编程容易、效率极高的算法。蓝桥杯软件类大赛中需要应用二分法的题目很常见。

二分法有整数二分和实数二分两种应用场景

二分法的概念

二分法的概念很简单,每次把搜索范围缩小为上一次的1/2,直到找到答案为止。

二分法的效率很高,只需计算log(n)次。

下面介绍二分法的模板代码bin_search()函数:

我们用猜数字的例子,先给数组初始化,然后定义你要猜的数,用二分法效率高。

对于二分法的讲解非常细致,都在注释中。

#include<bits/stdc++.h>
using namespace std;
int a[1000];
int bin_search(int *a, int n, int x) {   //在数组a中查找数字x,返回位置int left = 0, right = n;	//left 通常初始化为 0,表示搜索范围的左边界是数组的第一个元素;right通常初始化为 n(数组的长度),表示搜索范围的右边界是数组的最后一个元素的下一个位置。while (left < right) {int mid = left+(right-left)/2;   //mid的标准写法,建议这样写,不能用(left+right)/2,有可能会整数溢出的。 if (a[mid] >= x) right = mid;   //x小,在左边,把右边的一半砍掉,这里就不用加1了,我们本身就是大于等于x。 else             left = mid+1;	//加1的原因是我们要跳过 a[mid] 这个元素,因为它小于 x,我们要的是等于x的元素 cout<<a[mid]<< " ";              //输出猜数的过程    如果你想省略过程,可以注释掉这一行的输出语句。 }return left;    //返回left所在的索引,不要牵扯到right,避免混淆,right一开始是索引的下一个位置。 
}
int main() {int n = 100;for(int i=0; i<n; i++) a[i]=i+1;    //赋值,数字1~100int test = 54;                      //猜54这个数int pos = bin_search(a,n,test);cout<<"\n"<<"test="<<a[pos];    
}

bin_search()有3个重要点:区间左端点left、区间右端点right、二分的中位数mid。每次把区间缩小一半,把left或right移动到mid;直到left = right为止,即找到答案所处的位置。

二分法的作用:

二分法可以把一个长度为n的有序序列上O(n)的查找时间优化到O(logn)。

注意应用二分法的前提:序列是有序的,按从小到大或从大到小排序。

无序的序列无法二分,如果是无序的序列,则应该先排序再对其进行二分,先排序再二分,排序的复杂度是O(nlog2(n)),二分的复杂度是O(log2(n))。排序加二分的总复杂度是O(nlog2(n))。如果使用暴力法,直接在无序的n个数里面查找,最多查找n次,复杂度是O(n)的,比先排序再二分快。如果不是查找一个数,而是查找m个数,那么先排序再做m次二分的计算复杂度是O(nlog2(n)+ mlog2(n)),而暴力法的复杂度是O(mn),此时二分法远好于暴力法。

整数二分

在单调递增序列中查找x或者x的后继:

前面介绍的bin_search()函数就是“在单调递增序列中查找x或者x的后继”的模板代码。

二分函数都是一摸一样的,测试数据可以改一下,看看能不能查找后继:

int main() {int n = 100;for(int i=0; i<n; i++) a[i]=2*i+2;    //赋值,数字2~200,偶数int test = 55;                        //查找55或55的后继int pos = bin_search(a,n,test);cout<<"test="<<a[pos];//56   55没有,只能找56了。
}

在单调递增序列中查找x或者x的前驱:

#include<bits/stdc++.h>
using namespace std;
int a[1000];
int bin_search2(int *a, int n, int x) {int left = 0, right = n;while (left < right) {int mid = left + (right-left + 1)/2 ;   //+1是为了确保在 left 和 right 之间的元素数量是奇数时,mid 会指向中间元素;当元素数量是偶数时,mid 会指向中间两个元素的右侧那个元素。//这样做的原因是,我们希望在存在重复元素时,mid 尽可能向右偏移,从而找到最右侧的那个等于或小于 x 的元素。if (a[mid] <= x)  left = mid;else  right = mid - 1;}return left;
}
int main() {int n = 100;for(int i=0; i<n; i++) a[i]=2*i+2;   //赋值,数字2~200,偶数int test = 55;                       //查找55或55的前驱int pos = bin_search2(a,n,test);cout<<"test="<<a[pos]; //54
}

整数二分例题

例题1.分巧克力

2017年(第八届)省赛,lanqiaoOJ题号99

先试试暴力法:从边长为1开始到最大边长d,每个值都试一遍,一直试到刚好够分的最大边长为止。编程思路:边长初始值d = 1,然后d = 2、3、4……一个一个地试 。

代码:

#include<bits/stdc++.h>
using namespace std;
int h[100010],w[100010];//多申请10个空间 
int n,k;
bool check(int d) {             //检查够不够分int num=0;for(int i=0; i<n; i++)  num += (h[i]/d)*(w[i]/d);//假如,将6×5的巧克力的长边(6个单位)和宽边(5个单位)分别除以2×2的小正方形的边长(2个单位)。//这样可以得到长边可以切出3个2×2的巧克力,宽边可以切出2个2×2的巧克力。//接着,将长边和宽边切出的巧克力块数相乘,即3(长边切出的块数)× 2(宽边切出的块数)= 6。所以,一块6×5的巧克力可以切出6块2×2的巧克力。if(num>=k) return true;     //够分else       return false;    //不够分
}
int main() {cin >>n>>k;for(int i=0; i<n; i++)  cin>>h[i]>>w[i];  //长宽各自存在各自的数组中 int d=1;                    //正方形边长while(1) {if(check(d))  d++;      //边长从1开始,一个一个地试else          break;}cout << d-1;return 0;     //暴力求解只能过75的测试数据 ,最后两个测试数据错了,暂时不知道什么原因
}

整数二分法求解:

#include<bits/stdc++.h>
using namespace std;
int n,k;
const int N=100010;
int h[N],w[N];
bool check(int d) {int num=0;for(int i=0; i<n; i++)  num += (h[i]/d)*(w[i]/d);if(num>=k) return true;      //够分else       return false;     //不够分
}
int main() {cin >> n >> k;for(int i=0; i<n; i++)   cin>>h[i]>>w[i];int L=1, R=N;                //R的初值是100010//第一种写法:while(L<R) {int mid=(L+R+1) / 2;      //除以2,向右取整      不会整数溢出,直接L+Rif(check(mid))  L=mid;   //新的搜索区间是右半部分,R不变,调整L=midelse            R=mid-1; //新的搜索区间是左半部分,L不变,调整R=mid–1}cout << L;//第二种写法:/*  while(L<R) {int mid=(L+R) / 2;        //除以2,向左取整   不会整数溢出,直接L+Rif(check(mid)) L=mid+1;  //新的搜索区间是右半部分,R不变,更新L=mid+1else           R=mid;    //新的搜索区间是左半部分,L不变,更新R=mid}cout << L-1;    */return 0;
}

实数二分

与整数二分相比,实数二分的编程就容易多了,不用考虑整数的取整问题。实数二分的模板代码如下。

const double eps = 1e-7;                    //精度。
while(right - left > eps) {                 double mid = left+(right-left)/2;if (check(mid)) right = mid;          //判定,然后继续二分,check(mid)为true执行此语句else            left  = mid;
}

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

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

相关文章

AJAX——AJAX入门

1 什么是AJAX&#xff1f; Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一种用于在Web应用程序中实现异步通信的技术。 简单点说&#xff0c;就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON、XML、HTML和test文本等格式发送和接收数据。 AJAX最吸…

【深入理解BEVFormer】BEVFormer

任务场景 多模态融合和多传感器融合 BEV&#xff1a;鸟瞰图 这个特征空间与每个视角都相关 早期是用后融合&#xff0c;目前比较流行的是特征级融合 自身运动补偿&#xff1a;如果按照像素点进行特征对齐&#xff0c;需要指定偏移量 x y两个方向 特征空间是自己定义的&#xf…

NumPyML 源码解析(五)

numpy-ml\numpy_ml\preprocessing\nlp.py # 导入必要的库和模块 import re import heapq import os.path as op from collections import Counter, OrderedDict, defaultdict import numpy as np# 定义英文停用词列表&#xff0c;来源于"Glasgow Information Retrieval G…

NBlog个人博客部署过程记录 -- 后端springboot + 前端vue

项目是fork的Naccl大佬NBlog项目&#xff0c;页面做的相当漂亮&#xff0c;所以选择了这个。可以参考2.3的效果图 惭愧&#xff0c;工作两年了也每个自己的博客系统&#xff0c;趁着过年时间&#xff0c;开始搭建一下. NBlog原项目的github链接&#xff1a;Naccl/NBlog: &#…

毕业设计vue+php幼儿园网站系统yl567

幼儿园网站系统。采用vscode集成IDE对幼儿园网站系统统进行开发,整合系统的各个模块。 拟开发的幼儿园网站系统通过测试,确保在最大负载的情况下稳定运转,各个模块工作正常,具有较高的可用性。系统整体界面简洁美观,用户使用简单,满足用户需要。在因特网发展迅猛的当今社会,幼儿…

【计算机网络】网络层之IP协议

文章目录 1.基本概念2.协议头格式3.网段划分4.特殊的IP地址5.IP地址的数量限制6.私有IP地址和公网IP地址7.路由 1.基本概念 IP地址是定位主机的&#xff0c;具有一个将数据报从A主机跨网络可靠的送到B主机的能力。 但是有能力就一定能做到吗&#xff0c;只能说有很大的概率。…

[职场] 事业单位医疗岗常见的面试题目 #微信#微信#微信

事业单位医疗岗常见的面试题目 面试是步入社会以及就业过程中必须经历的一个首要阶段&#xff0c;也是实现就业必经的之道&#xff0c;可以说面试是双向选择和考试考核评价的过程&#xff0c;是企业选择应聘者的同时也应聘者也在选择企业。 一.常见的面试题目 1.对医学基础知…

计网体系结构

计算机网络的概述 概念 网络&#xff1a;网状类的东西或系统。 计算机网络&#xff1a;是一个将分散的、具有独立性功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。即计算机网络是互连(通过通信链路互连…

C/C++中的max函数如何使用?哪个头文件?多个数字可以用max吗?

在C中&#xff0c;max函数是一个非常实用的函数&#xff0c;它用于比较两个或更多数值并返回其中的最大值。这个函数在头文件中定义。 下面是如何在C中使用max函数的一些示例&#xff1a; #include <iostream> #include <algorithm> // 引入algorithm头文件以使…

前端可能需要的一些安装

Node.js Node.js 官网 Node.js 中文网 Node.js is an open-source, cross-platform JavaScript runtime environment. Node.js是一个开源、跨平台的JavaScript运行时环境。Recommended for most users 推荐大多数用户使用哔哩哔哩安装视频 安装 node.js 的时候&#xff0c;会…

Java的异常体系

一、体系简介 java中的Exception类的子类不仅仅只是像上图所示只包含IOException和RuntimeException这两大类&#xff0c;事实上Exception的子类很多很多&#xff0c;主要可概括为&#xff1a;运行时异常与非运行时异常。 在上述体系中&#xff0c;Error表示严重的系统错误&am…

【C++】 为什么多继承子类重写的父类的虚函数地址不同?『 多态调用汇编剖析』

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 本篇文章主要是为了解答有…

微信小程序框架阐述

目录 一、框架 响应的数据绑定 页面管理 基础组件 丰富的 API 二、逻辑层 App Service 小程序的生命周期 注册页面 使用 Page 构造器注册页面 在页面中使用 behaviors 使用 Component 构造器构造页面 页面的生命周期 页面路由 页面栈 路由方式 注意事项 模块化…

鸿蒙开发系列教程(二十二)--List 列表操作(1)

列表是容器&#xff0c;当列表项达到一定数量&#xff0c;内容超过屏幕大小时&#xff0c;可以自动提供滚动功能。 用于呈现同类数据类型或数据类型集&#xff0c;例如图片和文本 List、ListItemGroup、ListItem关系 列表方向 1、概念 列表的主轴方向是指子组件列的排列方…

【汇总】解决IndexedDB报Failed to execute ‘transaction‘ on ‘IDBDatabase‘

问题发现 再学习HTML5中&#xff0c;有介绍到 Web 存储&#xff0c;当代码编写完成后&#xff0c;运行报错 Failed to execute ‘transaction’ on ‘IDBDatabase’: One of the specified object stores was not found. 示例代码如下&#xff1a; <!DOCTYPE html> <…

1Coze平台介绍

2023年随着OpenAI推出GPT 3.5&#xff0c;AI赛道变得更加火热。GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;用于生成文本、理解语言和进行各种语言任务。GPT是由OpenAI开发的&#xff0c;它…

Tuxera NTFS2024版本的文件操作功能有哪些特点?

Tuxera NTFS通过集成先进的文件系统驱动程序和算法&#xff0c;实现了对多种文件系统的全面支持。具体来说&#xff0c;它具备以下功能和特点&#xff0c;使其能够支持多种文件系统&#xff1a; Tuxera NTFS2024下载如下: https://wm.makeding.com/iclk/?zoneid58824 先进的…

shumei 滑块 qd参数仿写记录

在对qd参数进行仿写的过程中&#xff0c;由于缺失很多js的基础知识&#xff0c;导致进展一度非常的缓慢&#xff0c;并且不知道自己的方向是不是正确的方向。在不知道自己的方向是否正确的时候&#xff0c;这个时候自己的投入的努力都是畏首畏尾。大概是一种&#xff0c;不知道…

基于剪贴板的文件传输方案

文章目录 背景原理步骤获取待上传文件的十六进制数据格式转换输出 背景 某次误删了环境上的C库之后想到的 什么都不可用了&#xff0c;但当前的ssh连接还在&#xff0c;echo命令和重定向符还可以使用 这就催生了我的想法&#xff1a;直接用echo -en “\xab\xcd” > file这样…

【c++】析构函数

1.特征 析构函数是特殊的成员函数&#xff0c;其特征如下&#xff1a; 1.析构函数名是在类名前加上字符~。 2.无参数无返回值类型。 3.一个类只能有一个析构函数。若未显式定义&#xff0c;系统会自动生成默认的析构函数。注意&#xff1a;析构函数不能重载。 4.对象生命周…