二分法讲解

news2025/1/19 3:34:49

目录

一、前言

二、二分法理论

1、引导:猜数游戏

2、理论背景:非线性方程的求根问题

1)非线性方程的近似解

2)搜索法和二分法

3、用二分的两个条件

4、二分法复杂度

三、整数二分

1、在单调递增序列中找 x 或者 x 的后继

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

3、对比

4、分巧克力(lanqiaoOJ题号99,2017年省赛)

(1)暴力法

(2)二分法

5、跳石头(lanqiaoOJ题号364)

(1)二分法套路题:最小值最大化、最大值最小化

6、青蛙过河(lanqiaoOJ题号2097)

四、实数二分

1、一元三次方程求解

(1)暴力法

(2)二分法

五、二分法习题


一、前言

二分法相信大家或多或少都有所了解,希望下面的内容能帮助大家对二分法有更深入更系统的理解。

二、二分法理论

1、引导:猜数游戏

一个 [1, 100] 内的数字,只需猜 7 次:

>50? 是。[1, 100] 二分,中位数 50,下一步猜 [51, 100]

>75? 否。[51, 100] 二分,中位数 75,下一步猜 [51, 75]

>63? 否。[51, 75] 二分,...

>56? 否。[51, 63] 二分,

>53? 是。

>54? 否。

=54? 是。

这个数是 54

  • 二分法:折半搜索
  • 二分的效率:很高,O(logn)
  • 例如猜数游戏,若n=1000万,只需要猜 log10^7 = 24 次
  • 二分法能把一个长度为 n 的有序序列上 O(n) 的查找时间,优化到了 O(logn)

猜数游戏的代码:

def bin_search(a,n,x):  #在数组a中找数字x,返回位置
    left=0
    right=n
    while left<right:
        mid=left+(right-left)//2
        if a[mid]>=x:
            right=mid
        else:
            left=mid+1
        print('[',left,right,']')   #打印猜数游戏的过程
    return left

n=100
a=[i for i in range(1,101)] #初始化1~100
test=54
pos=bin_search(a,n,test)
print("test=",a[pos])

2、理论背景:非线性方程的求根问题

  • 满足方程:f(x)=0 的数 x 称为方程的根。
  • 非线性方程:指 f(x) 中含有三角函数、指数函数或其他超越函数。
  • 非线性方程,很难或者无法求得精确解。
  • 二分法是一种求解的方法

1)非线性方程的近似解

【非线性方程】

在实际应用中,只要得到满足一定精度要求的近似解就可以了。

【根的存在性】

判定:设函数在闭区间 [a, b] 上连续,且 f(a)·f(b)<0,则 f(x) = 0 存在根。

【求根】

有两种方法:搜索法、二分法。

2)搜索法和二分法

【搜索法】

把区间 [a, b] 分成 n 等份,每个子区间长度是 Δx,计算点 xk = a + kΔx (k=0,1,2,3,4,.,n) 的函数值f(xk),若 f(xk) = 0,则是一个实根,若相邻两点满足 f(xk)·f(xk+1)<0,则在 (xk, xk+1) 内至少有一个实根,可以取 (xk+ xk+1)/2 为近似根。

【二分法】

如果确定 f(x) 在区间 [a, b] 内连续,且 f(a)·f(b)<0,则至少有一个实根。二分法的操作,就是把 [a, b] 逐次分半,检查每次分半后区间两端点函数值符号的变化,确定有根的区间。

3、用二分的两个条件

【条件】

上下界 [a, b] 确定

函数在 [a,b] 内单调。 

4、二分法复杂度

  • n 次二分后,区间缩小到 (b- a)/2^n。
  • 给定 a、b 和精度要求 ε,可以算出二分次数 n,即满足 (b - a)/2^n < ε
  • 二分法的复杂度是 O(logn) 的。
  • 例如,如果函数在区间 [0,100000] 内单调变化,要求根的精度是10^-8,那么二分次数是 44 次。

三、整数二分

操作的序列中都是整数

mid = (left+right) // 2

mid = left + (right-left) // 2

1、在单调递增序列中找 x 或者 x 的后继

  • 在单调递增数列 a[ ] 中查找某个数 x,如果数列中没有 x,找比它大的下一个数。
  • a[mid]>=x 时:x 在 mid 的左边,新的搜索区间是左半部分,left不变,更新 right= mid。
  • a[mid]<x 时:x 在 mid 的右边,新的搜索区间是半部分,right不变,更新 left=mid+1。
  • 代码执行完毕后,left=right,两者相等,即答案所处的位置。
def bin_search(a,n,x):  #在数组a中找数字x,返回位置
    left=0
    right=n     #左闭右开[0,n)
    while left<right:
        mid=left+(right-left)//2
        if a[mid]>=x:
            right=mid
        else:
            left=mid+1
        #print('[',left,right,']')   #打印猜数游戏的过程
    return left

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

  • 在单调递增数列 a[ ] 中查找某个数 x,如果数列中没有 x,找比它小的前一个数。
  • a[mid] <= x时,x 在 mid 的右边,新的搜索区间是右半部分,所以 right 不变,更新 left=mid;
  • a[mid] > x时,x 在 mid 的左边,新的搜索区间是左半部分,所以left不变,更新 right=mid-1。
def bin_search(a,n,x):  #在数组a中找数字x,返回位置
    left=0
    right=n     #左闭右开[0,n)
    while left<right:
        mid=left+(right-left+1)//2
        if a[mid]<=x:
            right=mid
        else:
            left=mid-1
        #print('[',left,right,']')   #打印猜数游戏的过程
    return left

3、对比

二分的应用场景:

1)存在一个有序的数列上;

2)能够把题目建模为在有序数列上查找一个合适的数值。

4、分巧克力(lanqiaoOJ题号99,2017年省赛)

【题目描述】

有 K 位小朋友到小明家做客。小明拿出了巧克力招待小朋友们。小明一共有 N 块巧克力,其中第 i 块是 Hi × Wi 的方格组成的长方形。为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。切出的巧克力需要满足:(1) 形状是正方形,边长是整数;(2) 大小相同。

例如一块 6×5 的巧克力可以切出 6块2×2 的巧克力或者 2块3X3 的巧克力。小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少?

【输入描述】

第一行包含两个整数 N, K (1<=N, K<=10^5)。以下 N 行每行包含两个整数 Hi, Wi ( 1<=Hi,  Wi<=10^5)。输入保证每位小朋友至少能获得一块 1×1 的巧克力。

【输出描述】

输出切出的正方形巧克力最大可能的边长。

(1)暴力法

  • 把边长从 1 开始到最大边长 d,每个值都试一遍,一直试到刚好够分的最大边长为止。
  • 编码:边长初始值 d=1,然后 d=2,3,4,一个个试。

复杂度:n 个长方形,长方形的最大边长 d。

check() 计算量是 O(n),做 d 次check(),总复杂度 O(n×d),n 和 d 的最大值是 10^5,超时。

def check(d):    #检查够不够分
    num=0
    for i in range(n):
        num+=(h[i]//d)*(w[i]//d)
    if num>=k:
        return True
    else:
        return False    #不够分

h=[0]*100010
w=[0]*100010
n,k=map(int,input().split())
for i in range(n):
    h[i],w[i]=map(int,input().split())
d=1     #正方形边长
while True:
    if check(d):
        d+=1    #变长从1开始,一个个地暴力试
    else:
        break
print(d-1)

(2)二分法

  • 一个个试边长 d 太慢了,现在使用二分,按前面的“猜数游戏”的方法猜 d 的取值。
  • 暴力法需要做 d 次 check(), 用二分法,只需要做 O(logd) 次 check(),总复杂度 O(nlogd)。
def check(d):    #检查够不够分
    num=0
    for i in range(n):
        num+=(h[i]//d)*(w[i]//d)
    if num>=k:
        return True
    else:
        return False    #不够分

h=[0]*100010
w=[0]*100010
n,k=map(int,input().split())
for i in range(n):
    h[i],w[i]=map(int,input().split())

L,R=1,100010
while L<R:
    mid=(L+R)//2
    if check(mid):
        L=mid+1
    else:
        R=mid
print(L-1)


#d=1     #正方形边长
#while True:
    #if check(d):
        #d+=1    #变长从1开始,一个个地暴力试
    #else:
    #   break
#print(d-1)

5、跳石头(lanqiaoOJ题号364)

【题目描述】

"跳石头"比赛在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 n 块岩石  (不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 m 块岩石 (不能移走起点和终点的岩石)。

【输入描述】

输入文件第一行包含三个整数 L, N, M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。接下来 N 行,每行一个整数,第 i 行的整数 Di (0<Di<L) 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。其中,0<=M<=N<=5×10^4,1<=L<=10^9。

【输出描述】

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

(1)二分法套路题:最小值最大化、最大值最小化

在 n 块岩石中移走 m 个石头,有很多种移动方法。在第 i 种移动方法中,剩下的石头之间的距离,有一个最小距离 ai。

在所有移动方法的最小距离 ai 中,问最大的 ai 是多少。在所有可能的最小值中,找最大的那个,就是 “最小值最大化”。

如果用暴力法找所有的组合,在 n 块岩石中选 m 个石头的组合情况太多,显然会超时。

转换思路,不去找搬走石头的各种组合,而是给出一个距离d,检查能不能搬走 m 块石头而得到最短距离 d。把所有的 d 都试一遍,肯定能找到一个最短的d。用二分法找这个 d 即可。

用二分法找一个最小距离 d。函数 check(d) 检查 d 这个距离是否合适。

lenn,n,m=map(int,input().split())
stone=[]            #石头i和到起点的距离
def check(d):
    num=0
    pos=0
    for i in range(0,n):    #0到n-1作为石头下标
        if stone[i]-pos<d:
            num+=1          #第i块可以搬走
        else:
            pos=stone[i]
    if num<=m:
        return True
    else:
        return False

for i in range(n):
    t=int(input())
    stone.append(t)
L,R=0,lenn
while L<R:
    mid=L+(R-L)//2
    if check(mid):
        L=mid+1
    else:
        R=mid-1
if check(L):
    print(L)
else:
    print(L-1)

6、青蛙过河(lanqiaoOJ题号2097)

【题目描述】

小青蛙住在一条河边,它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。河里的石头排成了一条直线,小青蛙每次跳跃必须落在一块石头或者岸上。不过,每块石头有一个高度,每次小青蛙从一块石头起跳,这块石头的高度就会下降1,当石头的高度下降到 0 时小青蛙不能再跳到这块石头上 (某次跳跃后使石头高度下降到 0 是允许的)。小青蛙一共需要去学校上 x 天课,所以它需要往返 2x 次。当小青蛙具有一个跳跃能力 y 时,它能跳不超过 y 的距离。请问小青蛙的跳跃能力至少是多少才能用这些石头上完 x 次课。

【输入格式】

输入的第一行包含两个整数 n, x,分别表示河的宽度和小青蛙需要去学校的天数。请注意 2x 才是实际过河的次数。第二行包含 n-1 个非负整数 H1, H2, …… , Hn-1,其中 Hi>0 表示在河中与小青蛙的家相距的地方有一块高度为 Hi 的石头,Hi=0 表示这个位置没有石头。

【输出格式】

输出一行,包含一个整数,表示小青蛙需要的最低跳跃能力。

【样例输入】

5 1

1 0 1 0

【样例输出】

4

【样例解释】

由于只有两块高度为 1 的石头,所以往返只能各用一块。第 1 块石头和对岸的距离为 4,如果小青蛙的跳跃能力为 3 则无法满足要求。所以小青蛙最少需要 4 的跳跃能力。

【评测用例规模与约定】

对于 30% 的评测用例,n<100;对于 60% 评测用例,n<1000;对于所有评测用例,1<=n<=105, 1<=x<=109, 1<=Hi<=104。

  • 往返累计 2x 次相当于单向走 2x 次。
  • 跳跃能力越大,越能保证可以通过 2x 次。
  • 用二分法找到一个最小的满足条件的跳跃能力。
  • 设跳跃能力为 mid,每次能跳多远就跳多远,用二分法检查 mid 是否合法。
def check(mid):
    for i in range(mid,n):
        if sum[i]-sum[i-mid]<2*x:
            return False
        return True

n,x=map(int,input().split())
h=list(map(int,input().split()))
sum=[0,h[0]]
for i in range(1,len(h)):
    sum.append(h[i]+sum[i])
L=0
R=100000
while L<=R:
    mid=(L+R)//2
    if check(mid):
        R=mid-1
    else:
        L=mid+1
print(L)

四、实数二分

  • 与整数二分法相比,实数二分容易多了,不用考虑整数的取整问题。
  • 两种写法:while、for
eps=0.00001     #精度,如果用for,可以不要eps
while right-left>eps:
#for i in range(100):
    mid=left+(right-left)/2
    if check(mid):
        right=mid       #判定
    else:
        left=mid

1、一元三次方程求解

【题目描述】

有形如:ax^3+ bx^2+ cx+ d = 0 这样的一个一元三次方程。给出该方程中各项的系数 (a,b,c,d均为实数),并约定该方程存在三个不同实根 (根的范围在 -100 至 100 之间),且根与根之差的绝对值>=1。要求由小到大依次在同一行输出这三个实根 (根与根之间留有空格),并精确到小数点后 2 位。

【输入描述】

输入一行,4 个实数 a, b, c, d。

【输出描述】

输出一行,3 个实根,从小到大输出,并精确到小数点后 2 位。

(1)暴力法

  • 本题数据范围小,可以用暴力法模拟。一元三次方程有 3 个解,用暴力法,在根的范围 [-100,100] 内一个个试。答案只要求 3 个精度为 2 位小数的实数,那么只需要试 200*100 = 20000 次就行了。
  • 判断一个数是解的方法:如果函数值是连续变化的,且函数值在解的两边分别是大于0和小于0,那么解就在它们中间。例如函数值 f(i) 和 f(j) 分别大于、小于0,那么解就在 [i, j] 内。

(2)二分法

  • 如果题目要 “精确到小数点后 6 位”,上面的暴力法需要计算 200*106 次,超时了。
  • 用二分法。题目给了一个很好的条件:根与根之差的绝对值大于等于 1。那么所有的 [i, i+1] 小区间内做二分查找就行。
def y(x):
    return a*x*x*x+b*x*x+c*x+d

n=input().split()
a,b,c,d=eval(n[0]),eval(n[1]),eval(n[2]),eval(n[3])

for i in range(-100,100):
    left=i
    right=i+1
    y1=y(left)
    y2=y(right)
    if y1==0:
        print("{:.2f}".format(left),end=" ")
    if y1*y2<0:
        #while right-left>=0.001:  #eps=0.001
        for i in range(100):    #100次二分
            mid=(left+right)/2
            if y(mid)*y(right)<=0:
                left=mid
            else:
                right=mid
        print("{:.2f}".format(right,end=" "))

五、二分法习题

以上, 二分法讲解

祝好​​​​​​​

 

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

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

相关文章

使用python-pptx创建PPT演示文档功能实践

python对PPT演示文档读写&#xff0c;是通过第三方库python-pptx实现的&#xff0c;python-pptx是用于创建和更新 PowerPoint&#xff08;.pptx&#xff09;文件的 Python 库。 关于PPT演示文档与幻灯片模板的内容不是本文的重点&#xff0c;在此略过。 1. PPT基本结构在pyth…

Sophus降维、升维与欧拉角、旋转向量的爱恨情仇

0. 简介 在面对二维与三维之间的转换时&#xff0c;我们常常会困惑该如何去转换&#xff0c;在G2O中存在有理想的坐标转换工具&#xff0c;但是在Sophus中却缺乏这样的手段。之前在Sophus处简要的介绍了一下SE(2)与SE(3)的转换&#xff0c;最近发现之前的文章这部分需要拿出来…

Leetcode:654. 最大二叉树(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 直接模拟&#xff08;递归)&#xff1a; 原理思路&#xff1a; 索引版本&#xff1a; 问题描述&#xff1a; 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&a…

Thymeleaf从入门到清晰使用

文章目录什么是thymeleaf&#xff1f;第一个Thymeleaf程序Thymeleaf详解配置常用标签最后什么是thymeleaf&#xff1f; 模板引擎&#xff1a; 前端交给我们的页面&#xff0c;是html页面&#xff0c;如果是以前开发&#xff0c;我们需要把他们转成jsp页面&#xff0c;jsp的好处…

ABB AC500 系列 PLC 与上位机iFix 的通讯配置

ABB PLC IP 及 MODBUS TCP/IP 协议设置 通过 IP config tool 配置设备 IP 在 软件中&#xff0c;有 3 种方式可以进入 IP config tool 的配置界面  双击 IP_settings&#xff0c;点击 IP config tool&#xff0c;即可进入 IP config tool 界面 点击菜单栏的 Tool→IP confi…

k8s 微服务spring boot JVM 监控

目录 1.前言 1.1 JVM监控方案 1.2 接入操作步骤 2. 服务开启actuator prometheus监控 2.1 示例参考添加依赖 2.2 配置prometheus监控 3 配置 prometheus 监控 4 配置jvm grafana dashboard 1.前言 服务 部署环境 监控 spring-demo k8s v1.22 Prometheus Operator …

进程相关概念

1、什么是程序&#xff0c;什么是进程&#xff0c;有什么区别 程序是静态的概念。例如&#xff1a;gcc xxx.c -o pro&#xff0c;磁盘中生成pro文件&#xff0c;叫做程序&#xff08;还未运行起来&#xff09; 进程是程序的一次运行活动&#xff0c;也就是程序跑起来了&#xf…

【Linux】信号机制(非实时信号)

目录 前言 一.信号的概念以及产生 1.什么是信号 2.信号分为两类 3.查看信号的命令 4.信号如何产生 1).通过软件产生 2).通过硬件产生 3).通过键盘组合键产生 二.信号的发送以及保存 1.信号如何发送 2.信号如何保存 1).概念 2).底层实现结构&&内核中的实现…

WampServer服务器设置控件

WampServer服务器设置控件 WampServer是一个web开发环境&#xff0c;是一个用于Windows操作系统的类似服务器的软件&#xff0c;由Romain Bourdon构建。该工具允许您开始构建web应用程序&#xff0c;并在Windows上使用Apache服务器2、PHP编程语言和MySQL数据库在本地网络上启动…

java 实现 springboot项目 使用socket推送消息,前端实时进行接收后端推送的消息

1 后端 1.1 添加依赖 在我们的springboot项目里面&#xff0c;添加依赖&#xff1b; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId><version>2.7.0</version>…

企业微信在职继承功能如何理解?怎么使用?

企业微信的在职继承功能就是企业管理员将在职员工的客户分配给其他在职员工跟进的一种方式&#xff0c;很方便&#xff0c;可以在工作出现变更时使用。 前言 企业微信之前的离职继承功能受到很多企业的青睐&#xff0c;企业能够将离职员工的客户分配给其他员工接手&#xff0c…

云天励飞在科创板获准注册:计划募资30亿元,陈宁为实际控制人

2023年1月10日&#xff0c;证监会发布公告&#xff0c;同意深圳云天励飞技术股份有限公司&#xff08;下称“云天励飞”&#xff09;首次公开发行股票注册。据贝多财经了解&#xff0c;云天励飞于2020年12月8日在科创板递交上市申请&#xff0c;2021年8月6日过会。 本次冲刺上市…

蓝队攻击的四个阶段(一)

蓝队的攻击是一项系统的工作&#xff0c;整个攻击过程是有章可循、科学合理的涵盖了从前期准备、攻击实施到靶标控制的各个步骤和环节。按照任务进度划分&#xff0c;一般可以将蓝队的工作分为4个阶段:准备工作、目标网情搜集、外网络向突破和内网横向拓展。第一阶段准备工作&a…

App开发提效法宝之插件技术

近年来技术革新频率越来越高&#xff0c;最近工作中经常有小伙伴问到插件技术的相关内容&#xff0c;今天就来跟大家系统的说清楚什么是插件技术以及它的好处。欢迎评论区交流哦&#xff01; 什么是插件技术&#xff1f; 插件技术指的是一种应用程序&#xff0c;遵循程序接口…

高温热水解预处理对厌氧消化期间污泥腐殖化的调控机制

期刊&#xff1a;Water Research 影响因子&#xff1a;9.13 发表时间&#xff1a;2022样本类型&#xff1a;污泥客户单位&#xff1a;同济大学凌恩生物客户同济大学发表在《Water Research》上的文章“The neglected effects of polysaccharide transformation on sludge humif…

振弦采集模块参数配置工具VMTool 的使用

振弦采集模块参数配置工具VMTool 的使用 准备工作 &#xff08; 1&#xff09; 将 VMXXX 模块的 UART_TTL、 RS232&#xff08; 或 RS485&#xff09; 接口与计算机的 COM 端口连接&#xff1b; &#xff08; 2&#xff09; 连接振弦传感器及温度传感器到 VMXXX 的对应接口&…

三菱FX3U系列PLC运动控制_伺服回原点的3种方法示例

三菱FX3U系列PLC运动控制_伺服回原点的3种方法示例 方法1: 运动的方向为圆形、环形、电机往一个方向转动; 只有一个原点开关,没有极限开关 如下图所示, 原点回归的方式为:启动回原点后,电机开始寻找原点开关,在找到原点开关的瞬间,开始减速;在离开原点开关的瞬间,电…

23. 反爬案例:不登录不给,要数据请先登录我的站点

登录之后&#xff0c;可以查看数据&#xff0c;是部分站点常用规则&#xff0c;本篇博客将在爬虫训练场中实现该需求。 文章目录安装必备模块建立 models建立 login_form 表单文件flask_wtf 中 FlaskForm 类建立登录视图函数配置 login.html 页面安装必备模块 实现 Python Fla…

Qt基于CTK Plugin Framework搭建插件框架--插件通信【事件监听】

文章目录一、前言二、事件三、类通信3.1、新建接收插件3.2、新建发送插件3.3、启用插件四、信号槽通信4.1、新建接收插件4.2、新建发送插件4.3、启用插件五、类通信和信号槽通信的区别六、插件依赖七、获取元数据一、前言 CTK框架中的事件监听&#xff0c;其实就是观察者模式&…

分享微信答题抽奖小程序制作步骤_可以做答题后抽奖活动吗

知识答题小程序如何制作&#xff1f;现在越来越多的企业和组织逐步进行各种获奖知识问答小程序。那么&#xff0c;如何制作一个答题小程序呢&#xff1f;今天&#xff0c;我们一起来看看~需要的老板不要走开哦~既然点进来了&#xff0c;那就请各位老板耐心看到最后吧~怎么做一个…