c++算法之二分

news2024/9/25 9:37:15

目录

二分法简介

解题步骤

整数二分

模板

例题

输入描述

输出描述

样例输入输出

浮点二分

模板

二分答案(最重要)

模板

例题 跳石头

题目描述

输入描述

输出描述

输入输出样例

例题 肖恩的苹果林

输入描述

输出描述

测试

例题 肖恩的乘法表


二分法简介

二分法是一种高效的查找方法,它通过将问题的搜索范围一分为二(两边具有明显的区别),迭代的缩小搜索范围,直到找到目标或确定目标不存在。

二分法使用于有序数据集合,并且每次迭代可以将搜索范围缩小一半

二分法本质也是枚举,但和暴力枚举不同,二分法利用数据结构的单调性减少了很多不必要的枚举,从而极大的提高了效率,一般可以将O(n)的枚举优化到O(logn)

解题步骤

1.研究并发现数据结构(或答案变量)的单调性

2.确定最大区间[l,r],确保分界点一定在里面,具有一定细节:若以r作为答案,那么答案区间在[l+1,r],若以l为答案,那么答案区间在[l,r-1]

3.确定check函数,一般为传入mid(区间中某个下标),返回mid所属区域或返回一个值,当check函数较简单时可直接判断

4.计算中点mid = (1+r)/2,用check判断该移动l或r指针,具体移动哪个需要根据单调性以及要求的答案来判断。

5.返回l或r,根据题意判断

整数二分

整数二分就是在一个已有的有序数组上,进行二分查找,一般为找出某个值的位置,或者是找出分界点。

这个数组肯定是开的下的,其数组大小一般在1e6以内。

模板

//找到升序数组a中的x第一次出现的位置
int l = 0,r = 1e9;
//注意这里的判断,这样可以保证l,r最终一定收敛到分界点
while(l+1!=r)//l r相邻退出
{
    int mid = (l+r)/2;
    //如果a为升序,说明mid偏大了,需要减小mid,就只能将r变小,即r = mid
    if(a[mid]>=x)r = mid;
    else l = mid;
}
cout<<r<<endl;

例题

给定一个数组,其采用如下代码定义

int data[200];
for(i = 0;i < 200;i++)data[i]=4*i+6;

先给定某个数(在data数组中),请你求出它在数组中的位置。

输入描述

输入一个待查找的整数(该整数一定在数组data中)

输出描述

输出该整数在数组中的指标

样例输入输出

输入262 输出64

#include<iostream>
using namespace std;
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int data[200];
	for (int i = 0; i < 200; i++)
	{
		data[i] = 4 * i + 6;
	}
	int x; cin >> x;
	int l = -1, r = 199;//为什么是-1 因为最后要返回r r的范围是l+1到r 即0到199
	while (l + 1 != r)
	{
		int mid = (l + r) >> 1;//二进制右移一位 相当于÷2
		if (data[mid] >= x)r = mid;
		else l = mid;
	}
	cout << r << endl;
	system("pause");
	return 0;
}

浮点二分

浮点二分不再是在有序数组上做二分查找,而是在某个实数范围内进行查找,因为实数域本身就是单调的,所以也满足单调性,和整数二分主要区别就在于使用的变量类型、退出的判断条件不同。

模板

//计算单调函数f(x)的零点
double l = 0,r = 1e9,eps = 1e-6;
//注意这里的判断条件,这样可以保证l,r最终一定收敛到分界点
while(r-l>=eps)//eps是一个极小量,设置为1e-6较合适
{
    double mid = (l+r)/2;
    //f(x)单调递增,f(mid)>=0,说明mid偏大了,需要减小mid,就只能将r变小,即r = mid
    if(f(mid))>=0)r = mid;
    else l = mid;
}
//最后返回l,r差别不大
cour<< r <<endl;

二分答案(最重要)

二分答案是二分法中最常见也最重要的题型,考察的比较灵活,需要选手从题目中发现某个单调的函数,然后对其二分

常见的模型是:

二分框架(时间复杂度O(logm)+check函数(时间复杂度O(n))

一般情况下,我们会将答案进行二分,然后再枚举出某个可能解后判断其是否可以更优或者是否合法,从而不断逼近最优解

二分答案的题的特征:如果已知某个答案,很容易判断其是否合法或更优。某些贪心问题可能可以转化成二分答案问题

模板

bool check(int mid)
{
    bool res = true;
    //do sth to check the authority of mid
    return res;
}
int main()
{
    int l = 0,r = 1e9;
    while(l+1!=r)
    {
        int mid = (l+r)/2;
        //具体写法需要根据题意修改
        if(check(mid))l = mid;
        else r= mid;
}
cout<<l<<endl;

例题 跳石头

题目描述

一年一度的"跳石头"比赛又要开始了!

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走M 块岩石(不能移走起点和终点的岩石)。

输入描述

输入文件第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。

接下来 N 行,每行一个整数,第 i 行的整数 (0<Di<L)表示第i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

其中,0≤5×104,1≤1090≤M≤N≤5×104,1≤L≤109

输出描述

输出只包含一个整数,即最短跳跃距离的最大值。

输入输出样例

    输入
    25 5 2
    2
    11
    14
    17
    21 

    输出
    4

#include<iostream>
using namespace std;
using ll = long long;
const int N = 5e4 + 9;
int a[N], L, n, m;

int check(int mid)
{
	//当最远跳跃距离为mid的情况下,至少需要搬走多少块石头
	int res = 0,lst=0;
	for (int i = 1,lst = 0; i <= n; i++)//lst表示上一块石头的位置
	{
		if (a[i] - a[lst] < mid)
		{
			res++;
			continue;
		}
		lst = i;

	}
	if (L - a[lst] < mid)
	{
		return m + 1;//这种情况不行,因为最后一块石头不能被搬走
	}
	return res;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> L >> n >> m;
	for (int i = 1; i <= n; ++i)cin >> a[i];

	ll l = 0, r = 1e9 + 5;
	while (l + 1 != r)
	{
		ll mid = (l + r) / 2;
		if (check(mid) <= m)l = mid;
		else r = mid;

	}
	cout << l << endl;

	return 0;
}

例题 肖恩的苹果林

肖恩有一大片农田,农田中有 N 个可以种植苹果树的位置。这些位置都分布在一条直线上,坐标是 x1,x2,..,xN 。肖恩得到了 M 个树苗,需要种到农田中的对应位置.
我们都知道两棵苹果树种的距离如果太近的话会互相争抢养分,导致两棵苹果树都会营养不良。所以肖恩认为相邻两棵苹果树之间的最近距离越大越好,那么请你帮肖恩算算最大的最近距离是多少?

输入描述

第一行输入两个整数N和M,两个数的意义和题面中描述相同
第二行输入N个数字,第i个数字 xi表示第i个可以种植苹果树的位置

输出描述

输出一个数字表示最大的最近距离

#include<iostream>
#include<algorithm>
using namespace std;
using ll = long long;
const int N = 5e4 + 9;
int x[N], n, m;

int check(int mid)
{
	
	int res = 0,lst=0;
	for (int i = 1, lst = 0; i <= n; i++)
	{
		if (lst && x[i] - x[lst] < mid)continue;
		res++, lst = i;
	}
	return res;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >>n >> m;
	for (int i = 1; i <= n; ++i)cin >> x[i];
	sort(x + 1, x + 1 + n);

	ll l = 0, r = 1e9 + 5;
	while (l + 1 != r)
	{
		ll mid = (l + r) / 2;
		if (check(mid) >= m)l = mid;//最多能种多少树 大于m 说明间隙小了 要增大
		else r = mid;

	}
	cout << l << endl;

	return 0;
}

测试

5 3
1 3 4 8 9
3

例题 肖恩的乘法表

#include<iostream>
#include<algorithm>
#include<windows.h>
using namespace std;
using ll = long long;
const int N = 5e4 + 9;
ll n, m, k;

ll check(ll mid)
{
	
	ll res = 0;
	for (int i = 1; i <= n; i++)//每一行多少个数字<mid
	{
		res += min(m, mid / i);
	}
	return res;
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >>n >> m>>k;

	ll l = 0, r = 1e14;
	while (l + 1 != r)
	{
		ll mid = (l + r) >> 1;
		if (check(mid) >= k)r = mid;
		else l = mid;

	}
	cout << r << endl;

	return 0;
}

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

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

相关文章

GBASE南大通用数据库如何检索单行

SELECT 语句返回的行集是它的活动集。单个 SELECT 语句返回单个行。您可使用嵌入式 SELECT 语句来从数据库将单个行检索到主变量内。然而&#xff0c;当 SELECT 语句返回多行数 据时&#xff0c;程序必须使用游标来一次检索一行。在 检索多行 中讨论“多行”选择操作。 要检索单…

png格式图片怎么转换?分享3个转换的方法

随着互联网的普及和自媒体的发展&#xff0c;我们每天都会遇到各种图片格式&#xff0c;其中PNG格式因其透明背景和高质量的图像而受到广泛欢迎。然而&#xff0c;有时候我们需要将PNG格式的图片转换成其他格式以满足不同的需求。那么&#xff0c;如何轻松转换PNG格式的图片呢&…

在全志T113-i平台上实现H.265视频解码步骤详解

H.265&#xff0c;也被称为HEVC(HighEfficiency Video Coding)&#xff0c;作为H.264的继任者&#xff0c;提供了更好的视频压缩和更高的视频质。H.265通过引入更多先进的编码技术&#xff0c;如更强大的运动估计和更高效的变换编码&#xff0c;对比H.264进行了改进。这些改进使…

代码随想录 Leetcode203. 移除链表元素

题目&#xff1a; 代码(首刷看解析 2024年1月11日&#xff09;&#xff1a; class Solution { public:ListNode* removeElements(ListNode* head, int val) {if(headnullptr) return nullptr;ListNode* BeforeHead new ListNode(0,head);ListNode* temp BeforeHead;while(te…

seata分布式事务(与dubbo集成)

1.seata是什么? Seata 是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 2.seata的注解 GlobalTransactional&#xff1a;全局事务注解&#xff0c;添加了以后可实现分布式事务的回滚和提交&#xff0c;用法与spring…

C语言从入门到实战——数据在内存中的存储方式

数据在内存中的存储方式 前言1. 整数在内存中的存储2. 大小端字节序和字节序判断2.1 什么是大小端2.2 为什么有大小端2.3 练习2.3.1 练习12.3.2 练习22.3.3 练习32.3.4 练习42.3.5 练习52.3.6 练习6 3. 浮点数在内存中的存储3.1 练习3.2 浮点数的存储3.2.1 浮点数存的过程3.2.2…

模拟退火算法(SA)解决旅行商(TSP)问题的python实现

旅行商问题 旅行商问题&#xff08;Travelling Salesman Problem, 简记TSP&#xff0c;亦称货郎担问题)&#xff1a;设有n个城市和距离矩阵D [dij]&#xff0c;其中dij表示城市i到城市j的距离&#xff0c;i, j 1, 2 … n&#xff0c;则问题是要找出遍访每个城市恰好一次的一…

扫码看图怎么做轮播效果?多组图片用扫码查看的方法

图片通过二维码来做展示现在是很常见的一种方式&#xff0c;用这种方式可以用于多种图片格式。那么当我们需要将图片做成多个分组的轮播图样式展示时&#xff0c;有什么好的方法能够做成这个效果呢&#xff1f;下面就来教大家使用二维码生成器制作图片二维码的操作方法&#xf…

BioTech - 蛋白质结构、核酸结构、小分子构象的预测

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135568438 生物结构预测是指根据生物分子的序列信息&#xff0c;推断其在空间中的三维形状和排列。生物结构预测对于理解生物分子的功能、相互作用…

LLM之RAG实战(十四)| 利用LongContextRetriver克服RAG中的中间丢失现象

人类和大型语言模型&#xff08;LLM&#xff09;都有一个共同的行为模式&#xff1a;他们往往擅长处理位于给定内容开头或结尾的信息&#xff0c;而中间的信息往往会被忽视。 来自斯坦福大学、加州大学伯克利分校和Samaya AI的研究人员在论文《Lost in the Middle: How Languag…

精确掌控并发:分布式环境下并发流量控制的设计与实现(一)

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;10&#xff09;篇。 本篇主要讲清楚常用的并发流量控制方案&#xff0c;包括固定窗口、滑动窗口、漏桶、令牌桶、分布式消息中间件等&#xff0c;以及各种方案在支付系统不同场景下的应用。 在非支付场景&a…

【LabVIEW FPGA入门】使用LabVIEW FPGA进行编程并进行编译

在本文中会进行一个简单的FPGA编程演示&#xff0c;这通常可以验证编译工具链是否正常使用。在LabVIEW FPGA中和rt、PC编程一样使用数据流编程&#xff0c;但是需要注意的是FPGA中有些函数是不可以用的&#xff0c;因为这些函数很占用资源&#xff0c;且FPGA只能同时下载运行一…

6.2 声音编辑工具GoldWave5简介(5)

6.2.4录制声音 利用Windows自带的“录音机”录制声音时&#xff0c;只能录制最大时长为1分钟的声音&#xff0c;而利用GoldWave5&#xff0c;可以录制时长长达277小时以上的声音&#xff0c;而且&#xff0c;录制完成后&#xff0c;还可以很方便地对声音进行处理、转换等操作。…

【MIT 6.S081】2020, 实验记录(3),Lab: page tables

目录 TaskTask 1: Print a page table Task Task 1: Print a page table 该实验需要增加一个 vmprint 函数&#xff0c;用于打印一个 page table&#xff0c;实现过程可以参考 vm.c 文件中的 freewalk() 函数。 在 defs.h 中增加 vmprint 的定义&#xff1a; void …

海外融合CDN之火伞云

在当今互联网全球化的时代&#xff0c;出海业务已经成为许多企业的必然选择。在海外市场上&#xff0c;快速、稳定的内容传输对于企业的成功至关重要。然而&#xff0c;如何合理的运用多家CDN供应商的资源实现智能化的调度&#xff0c;以及如何与业务更紧密地结合起来&#xff…

前端背景收集之烟花背景

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f380;源码如下&#xff1a; &#x1f412;个人主页 &#x1f3c5;Vue项目常用组件模板仓库 &#x1f4d6;前言&#xff1a; 本篇博客主要提供前端背景收集之烟花背景…

基于微信小程序的音乐平台 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首音乐4.2 新增音乐4.3 新增音乐订单4.4 查询音乐订单4.5 新增音乐收藏 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的音乐平台&#xff0c;包含了音乐…

七通道NPN 达林顿管GC2003,专为符合标准 TTL 而制造

GC2003 内部集成了 7 个 NPN 达林顿晶体管&#xff0c;连接的阵列&#xff0c;非常适合逻辑接口电平数字电路&#xff08;例 如 TTL&#xff0c;CMOS 或PMOS 上/NMOS&#xff09;和较高的电流/电压&#xff0c;如电灯电磁阀&#xff0c;继电器&#xff0c;打印机或其他类似的负…

C++力扣题目513找树左下角的值

给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 思路 本题要找出树的最后一行的最左边的值。此时大家应该想…

四大会计假设

目录 一. 会计主体假设二. 持续经营假设三. 会计期间假设四. 货币计量假设 \quad \quad 一. 会计主体假设 \quad 会计主体: 会计工作为其服务的特定单位或组织。 会计主体的定义 1.具有一定数量的资金。 2.进行独立的生产经营或其他活动。 3.实行独立核算。 \quad 会计主体假设…