二分

你说的曾经没有我的故事 提交于 2020-02-02 13:57:15

二分

二分是一种思想,其不仅限于查找。其中查找是一个很典型的应用。个人对二分的理解:如果一个题目告诉你最大答案范围,即在那个范围里肯定存在一个答案,那么就可以用二分(查找很典型了吧,不过查找也可以找不到,最后arr[mid]!=num to be find)。

二分查找是一种查找效率非常高的算法,时间复杂度为O(log2n)不过前提是数组提前排列好顺序,其实现代码如下:

1.二分递归版本

int binarysearch(int *arr,int key,int l,int r)
{
    int mid=(r+l)>>1;
    if(l>r) return -1;
    else if(key==arr[mid])  return mid;
    else if(key>arr[mid])   return binarysearch(arr,key,mid+1,right);
    else if(key<arr[mid])   return binarysearch(arr,key,left,mid-1);
    return -1;
}

2.二分非递归版本

int binarySearch1(int *a,int n,int target)
{
    int l=1,r=n,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(a[mid]>=target)      r=mid;
        else    l=mid+1;
    }
    if(arr[l]==target)  return l;
    return -1;
}

【题意】:输入n(字符长度),k(最多关灯次数),字符串中1表示开灯,0表示关灯,问最少每次要关几盏灯。

思路:直接二分答案,答案肯定在1~n之内。看代码:

#include<bits/stdc++.h>

using namespace std;
const int maxn=5e5+10;
char s[maxn];
int n,k,posr,posl;
bool check(int x)
{
    int start=posl;
    int cnt=0;
    while(start<=posr)
    {
        start+=x;
        cnt++;
        while(s[start]!='1')    start++;
    }
    if(cnt>k)    return 0;        
    if(cnt<=k)   return 1;      
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&k);
        scanf("%s",s+1);
        posr=n,posl=1;
        while(s[posr]!='1') posr--;
        while(s[posl]!='1') posl++;
        int l,r,mid;
        l=1,r=n;
        mid=(l+n)>>1;
        while(l<r)              //二分答案每次检验答案是否符合题意
        {
            mid=(l+r)>>1;
            if(check(mid))   r=mid;
            else             l=mid+1;
        }
        mid=(l+r)>>1;
        printf("%d\n",mid);
    }
}

注意:整数上的二分条件为l=mid+1,r=mid;而实数上的二分条件为:l=mid,r=mid

三分及其应用

这里的单峰函数是指有唯一一个极大值点,且峰值左右两边严格单调,这时可以选两个点将函数三分,show code:

#include <bits/stdc++.h>

using namespace std;
const double eps=1e-7;
int n;
double l,r,idx[20];
double f(double x)
{
    double ans=0;
    for(int i=0;i<=n;++i)
        ans+=idx[i]*pow(x,n-i);
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>l>>r;
    for(int i=0;i<=n;++i)   cin>>idx[i];
    while(r-l>eps)          //注意退出循环的条件,一般高两个精度即可
    {
        double mid=(l+r)/2;
        if(f(mid-eps)<f(mid+eps))   l=mid;
        else r=mid;
    }
    printf("%.5lf\n",r);
    getchar();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!