• 浅谈二分和二分答案


    一般来讲我们会在以下情况用到二分:

    • 求单调函数的零点
    • 求一堆东西的最小值最大是多少
    • 很难直接算出答案,但是很好判定答案合不合法

    如果想学就继续看吧!

    二分查找

    二分是一种可以再(mathcal{O}(mathrm{ch}log m))(m)为数据规模,(mathrm{ch})为判断状态合法性check()函数时间复杂度)时间复杂度内求解问题的方法,主要是一个分治,每次将搜索范围减半。

    我们以二分查找引入。

    有一个有序序列,二分查找的思想如下:

    1.定义L,R,mid代表答案在[L,R]内,中点为mid
    2.查找mid所在值,如果mid大于查找值,搜索范围定为[L,mid],如果mid小于查找值,搜索范围定为[mid,R],如果查找到了,则返回L
    3.将mid重新设为中点,并调至2

    • 二分查找的时间复杂度是(mathcal{O}(log n))
    • 顺序查找的时间复杂度是(mathcal{O}(n))

    现在比较它们两个:

    例1:

    例2:

    代码的话在这:

    //二分查找(递归)
    int binarySearch(int list[],int left,int right,int number)
    {
        if(list==NULL)  return -1;
        int index=0;
        int mid=(right+left)/2;
        if(left>right)
            return -1;
        if(number==list[mid])
        {
            index=mid;
            return index;
        }
        else if(number>list[mid]) binarySearch(list,mid+1,right,number);
        else binarySearch(list,left,mid-1,number);
    }
    //二分查找(循环)
    int binarySearch(int list[],int left,int right,int number)
    {
        if(list==NULL) return -1;
        while(left<right)
        {
            int mid=(right+left)/2;
            if (list[mid] == number) return mid;
            else if (number > list[mid]) left=mid+1;
            else if (number < list[mid]) right=mid-1;
        }
        return -1;
    }
    

    二分答案

    二分答案嘛,就是想二分查找一样,只是判断改了,模板:

    while(l<r)
    {
        mid=(l+r)/2;
        if (check(mid)) r=mid;
        else l=mid+1;
    }
    

    check一般是贪心DP

    具体应用

    比如方程求根啦:

    题目描述

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

    提示:记方程(f(x)=0),若存在两个数(x_1)(x_2),且(x_1<x_2)(f(x_1) imes f(x_2)<0),则在((x_1,x_2))之间一定有一个根。

    输入格式

    一行,(4)个实数(A,B,C,D)

    输出格式

    一行,(3)个实根,并精确到小数点后(2)位。

    输入输出样例

    输入

    1 -5 -4 20

    输出

    -2.00 2.00 5.00

    这提示明摆着疯狂暗示我们二分啊,按提示二分即可:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define db double
    using namespace std;
    db a,b,c,d,f1,f2;
    int cnt=0;
    db check(db x){return a*x*x*x+b*x*x+c*x+d;}
    int main()
    {
        cin>>a>>b>>c>>d;
        db l,r,mid;
        for(db i=-100;i<=100;++i)
        {
            f1=check(i);
            f2=check(i+1);
            if(!f1){printf("%.2lf ",i);cnt++;}
            if(f1*f2<0)
            {
                l=i,r=i+1;
                while(r-l>=0.001)
                {
                    mid=(l+r)/2;
                    if (check(mid)*check(r)>0) r=mid;
                    else l=mid;
                }
                printf("%.2lf ",r);
                cnt++;
            }
            if (cnt==3) break;
        }
        return 0;
    }
    

    小学奥数啦:

    题目描述

    甲、乙两人同时从A地出发要尽快同时赶到B地。出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人。已知甲、乙两人的步行速度一样,且小于车的速度。问:怎样利用小车才能使两人尽快同时到达。

    输入格式

    仅一行,三个数据分别表示AB两地的距离s,人的步行速度a,车的速度b。

    输出格式

    两人同时到达B地需要的最短时间,保留6位小数。

    输入输出样例

    输入

    120 5 25

    #### 输出
    

    9.600000

    这种题想不出来也可以二分啊。

    思路如下

    然后二分C点啦:

    #include<cstdio>
    #include<cmath>
    int main()
    {
        double s,s1,s2,v1,v2,t1,t2,p;
        double a,b;
        scanf("%lf%lf%lf",&s,&v1,&v2);
        s1=0;
        s2=s;
        do
        {
            p=(s1+s2)/2.0;
            a=p/v2;
            b=(p-a*v1)/(v1+v2);
            t1=a+(s-p)/v1;
            t2=a+b+(s-(a+b)*v1)/v2;
            if(t1<t2)
            	s2=p;
            else
            	s1=p;
        }
        while (fabs(t1-t2)>1e-8);
        printf("%.6lf",t1);
        return 0;
    }
    
  • 相关阅读:
    嵌入式工程师C语言面试常见的0x10个问题
    C语言初学者网站推荐
    strlen和sizeof
    基于Docker搭建GitLab和Maven私服
    linux暴露端口可以被外部访问
    MySQL新增用户及赋予权限
    Docker添加域名解析
    Netstat 网络命令详解
    Mysql索引太长导致同步数据结构失败解决方法
    完美解决Cannot download "https://github.com/sass/node-sass/releases/download/binding.nod的问题
  • 原文地址:https://www.cnblogs.com/CDOI-24374/p/12274830.html
Copyright © 2020-2023  润新知