二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

您所在的位置:网站首页 数学考试怎么搜答案 二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

二分查找 & 二分答案 万字详解,超多例题,带你学透二分。

2024-06-02 05:22| 来源: 网络整理| 查看: 265

很多人对二分感到很苦恼,很困惑,可能是因为二分的边界很难掌握,也许是判断条件难写…

然而,很幸运,你找到了这篇文章,仔细看下去,这篇文章将带你学透二分!!!

二分可以简单分为二分查找与二分答案。

可能你听说过二分查找,二分查找和二分答案是不是一回事呢?答案是否定的。二分查找只是单纯的查找就可以了,简单的控制好边界条件。而二分答案也许稍复杂些。

首先,我们看一下二分的模板: 模板1: while (l int mid = l + r + 1 >> 1; //(l+r+1)/2 if (check(mid)) l = mid; else r = mid - 1; }

看到这,以后的你就不会因为边界问题而困惑了!!!

第一个模板是尽量往左找目标,第二个模板是尽量往右找目标。

只要是往左找答案,就用第一个模板,mid不用加一,r=mid,l加一; 只要是往右找答案,就用第二个模板,mid要加一,l=mid,r要减一;

二分套这两个模板,肯定没错!(只要判断条件写对)亲测有效!!! 下面的题目更能证明这句话!

这两个模板一定要牢牢记住哦

当然,二分可能在实数中进行,那自然少不了浮点二分。

模板3:(浮点二分) while(r-l>1e-5) //需要一个精度保证 { double mid = (l+r)/2; if(check(mid)) l=mid; //或r=mid; else r=mid; //或l=mid; }

浮点二分就相对简单多了,因为浮点除法不会取整,所以mid,l,r,都不用加1或减1.

我们先来学二分查找:

二分查找也称折半查找,顾名思义,就是每次查找去掉不符合条件的一半区间,直到找到答案(整数二分)或者和答案十分接近(浮点二分)。

光说不练假把式,来个例题:

例题1——查找

在这里插入图片描述 分析:这题就是典型的二分查找入门题。

首先,区间是有单调性的,查找第一次出现的位置,如果查到一个值比目标值大,就把右半边放弃,因为右半边肯定也比目标值大;同样,如果查到值比目标值小,那就放弃左半边。

本文的所有例题都有分析,题解,并注上详细注释。先自己尝试一下,再看题解哦。

code: #include using namespace std; const int N=1000010; int a[N],x,q,n; int main(){ cin>>n>>q; for(int i=1;i>a[i]; while(q--) { cin>>x; int l=1,r=n; //左右边界 while(l //如果找不到这个值 cout int l=i+1,r=n; //寻找A第一次出现的位置,使得A-B=C while(l int mid=l+r+1>>1; if(a[mid] cin>>x; int l=1,r=n+1; //r设为n+1 while(l cin>>x; int t=lower_bound(a+1,a+n+1,x)-a; //如果分数线都比估分低,那返回的位置是n+1,否则返回第一个大于等于估分的位置。 if(a[t]-x sumt=sumt+sumt*mid-t; } if(sumt > 0) return 1; //这里是>0, 感谢评论区小伙伴提醒~ return 0; } int main(){ cin>>sum>>t>>mon; double l=0,r=500; //答案范围尽量开大些 while(r-l>1e-5) //精度保证 { double mid=(l+r)/2; if(check(mid)) r=mid; //如果最后还不完了,说明利率高了 else l=mid; } printf("%.1f",l*100); return 0; }

至此,相信你已经对二分查找有一个更加清晰的认识了。

课后再来几个练习题吧: 整数二分: 1、 数的范围 2、 砍树 实数二分: 3、 数的三次方根 4、 一元三次方程求解

学会了二分查找,来学二分答案!

首先:

二分查找与二分答案有何区别?

二分查找:在一个已知的有序数据集上进行二分地查找 二分答案:答案有一个区间,在这个区间中二分,直到找到最优答案

什么是二分答案?

答案属于一个区间,当这个区间很大时,暴力超时。但重要的是——这个区间是对题目中的某个量有单调性的,此时,我们就会二分答案。每一次二分会做一次判断,看是否对应的那个量达到了需要的大小。 判断:根据题意写个check函数,如果满足check,就放弃右半区间(或左半区间),如果不满足,就放弃左半区间(或右半区间)。一直往复,直至到最终的答案。

其实,上面二分查找的例4,寻找的那个区间就是答案区间。

这不就相当于高中做选择题的时候,完了,不会做,那咋搞,把四个选项代进去看看对不对吧!哪个行得通那个就是答案!!

只不过我们现在要找的是最大的或者最小的答案。

如何判断一个题是不是用二分答案做的呢? 1、答案在一个区间内(一般情况下,区间会很大,暴力超时) 2、直接搜索不好搜,但是容易判断一个答案可行不可行 3、该区间对题目具有单调性,即:在区间中的值越大或越小,题目中的某个量对应增加或减少。

此外,可能还会有一个典型的特征:求...最大值的最小 、 求...最小值的最大。 1、求...最大值的最小,我们二分答案(即二分最大值)的时候,判断条件满足后,尽量让答案往前来(即:让r=mid),对应模板1; 2、同样,求...最小值的最大时,我们二分答案(即二分最小值)的时候,判断条件满足后,尽量让答案往后走(即:让l=mid),对应模板2;

先看一个经典的二分答案入门:

例1——木材加工在这里插入图片描述 分析:看,答案就在区间(1,100000000)里,就等着我们找呢,暴力肯定超时,那可能就用二分。 满足条件:

1,答案在一个区间里。 2,如果给一个答案,给目标一个小段的长度,很容易判断是否到K个了。 3,具有单调性,目标小段越长,那能切出的段数越少,目标小段越短,能切出的段数越多。而最终需要K个,从而很容易判断一个答案行不行。

一看求啥,求最长长度,最长?这不,关门打狗,模板2! ! 那,判断条件?模板2,如果满足判断,l=mid。啥叫满足呢?那肯定是满足需要的段数了呗! code: #include using namespace std; const int N=1e5+10; long long a[N],n,m,sum,maxa; int check(int mid) { int sum=0; for(int i=1;i cin>>n>>m; for(int i=1;icout int cnt=0; int i=0,now=0; //i表示目标位置,now为当前位置。 while(i //两石头间距离小于mid,mid不是最短距离,不满足,移走该石头 cnt++; } else{ //符合,跳过去 now=i; } } if(cnt cin>>a[i]; if(a[i] int mid=l+r+1>>1; if(check(mid)) l=mid; //要的是距离的最大,所以尽可能地往右走 else r=mid-1; } cout i++; if(a[i]-a[now]>=mid){ //保证拿走的瓶盖间距大于等于mid,才拿这个瓶盖,否则不能保证mid为最短距离 now=i,cnt++; } } if(cnt+1>=m) return 1; //如果拿出的总个数大于等于m,都能保证拿走的瓶盖间距大于等于mid,那拿出来m个,肯定也能满足!! return 0; } int main(){ cin>>n>>m; for(int i=1;i int mid=l+r+1>>1; if(check(mid)) l=mid; else r=mid-1; } cout sum+=a[i]; if(sum+a[i+1]>mid) cnt++,sum=0; //不能满足 "区间间距小于最大距离",那就分段 } if(cnt+1 cin>>a[i],summ+=a[i]; if(a[i]maxa) maxa=a[i]; } int l=maxa,r=summ; //l要设为maxa,所有段的最大值肯定大于等于maxa while(l


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3