整数二分和浮点数二分算法

1.整数二分:

注意,二分不一定是整个序列满足单调性,但是满足单调性可以用二分,也就是说,二分是是单调性的必要不充分条件。首先,把整个序列分为左右两段,先说左段,然后取中间值mid=(L+r+1)/2,加1的目的是防止越界,假如说L=r-1,即L和r只差一位,则r=L+1,如果说mid=(L+r)/2,那么mid就等于(2L+1)/2,然后下取整就等于L了,那么就会形成死循环。如果说q[mid]<=我们要找的值(令它为x),那么L就等于mid,否则r=mid-1。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int n,m;//数字个数和询问次数 
int q[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&q[i]);
    }
    while(m--){
        int x;
        scanf("%d",&x);
        int l=1,r=n;
        while(l<r){
            int mid=(l+r+1)/2;
            if(q[mid]<=x) l=mid;
            else r=mid-1;
        }
        if(q[l]!=x) cout<<-1<<" ";//没找到 
        else cout<<l<<" ";//找到了 
    }
    return 0;
}

再说右段,还是先取中间值mid=(L+r)/2,这回不用+1了 ,如果说q[mid]>=x,那么r就等于mid,否则L=mid+1。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int n,m;
int q[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&q[i]);
    }
    while(m--){
        int x;
        scanf("%d",&x);
        int l=1,r=n;
        while(l<r){
            int mid=(l+r)/2;
            if(q[mid]>=x) r=mid;
            else l=mid+1;
        }
        if(q[l]!=x) cout<<-1<<" ";
        else cout<<l<<" ";
    }
    return 0;
}

总结一下,如果题里说要求满足条件的最大值,那么就用左段,要求满足条件的最小值,就用右段。例如,洛谷上的二分模板题(p2249),它说要输出数字在序列中第一次出现的编号,那么我们就用右段。(如果不理解+1和不加1的事,就硬背吧)。

2.浮点数二分:

浮点数二分没有那么麻烦,不用讨论边界问题(不用加减1),因为两个数之间还有无穷多个小数,而整数二分的话,两个数之间的数不能取到,所以要讨论边界问题,但是浮点二分有精度问题(首先取mid中间值,然后把L或r移到mid这里,然后比如看左段,再取mid,再把L或r移到这里,然后再取mid,......,发现L和r的距离会越来越小,但是它一定存在)。比如,给定一个实数x,要求根号x,首先划定一个区间[0~x],令这个根号x=a,那么在0~a这个区间的数一定<=x,在a~x这个区间的数一定>=x。

#include<bits/stdc++.h>
using namespace std;
int main()
{
    double x;
    cin>>x;
    double l=0,r=x;
    while(r-l>1e-8){//这里不能写l<r,因为这两个数无论多小,也是可以比较出大小的 ,这里是保留6位小数 
        double mid=(l+r)/2;
        if(mid*mid>=x) r=mid;//这里不可以用"^"这个符号,它表示异或 
        else l=mid; 
    }
    printf("%lf\n",l);
    return 0;
}

小技巧:比如题里说要求保留2位小数,那么L-r>1e-4,保留4位,L-r>1e-6,保留6位,L-r>1e-8,总结就是保留x位小数,L-r>1e-(x+2)。还有就是如果给了实数x的范围(比如说-10000~10000),那么L=-10000,r=10000。 

  • 23
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值