二分
二分
二分是一种思想,其不仅限于查找。其中查找是一个很典型的应用。个人对二分的理解:如果一个题目告诉你最大答案范围,即在那个范围里肯定存在一个答案,那么就可以用二分(查找很典型了吧,不过查找也可以找不到,最后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();
}