二分

二分

二分是一种思想,其不仅限于查找。其中查找是一个很典型的应用。个人对二分的理解:如果一个题目告诉你最大答案范围,即在那个范围里肯定存在一个答案,那么就可以用二分(查找很典型了吧,不过查找也可以找不到,最后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();
}
posted @ 2020-02-02 12:45  StungYep  阅读(680)  评论(0编辑  收藏  举报