赞
踩
二分的本质不是单调性,没有单调性也可以用二分
二分的本质是边界,在区间上定义某种性质,使得整个区间一分为二,一半区间满足这种性质,另一半区间不满足这种性质,那么二分可以寻找到性质的边界
既可寻找绿颜色边界,也可寻找红颜色边界
红色为不满足性质的区间,绿色为满足性质的区间
1.找中间值mid=(l+r)>>1;
2.check(mid)满足性质时为true
3.如果check(mid)=true
说明在右边区间(绿色)找到了mid,应该到[l.mid]区间找答案
如果check(mid)=false
说明在左边区间(红色)找到了mid,应该到[mid+1,r]区间找答案
while(l<r){
int mid=(l+r)>>1;
if(check(mid)==true)r=mid
else l=mid+1;
}
1.找中间值mid=(l+r+1)>>1;
当l=r-1时, 如果check为true l=mid mid=l+r>>1=l 会发生死循环
2.check(mid)不满足性质时为true
3.如果check(mid)=true
说明在左边区间(红色)找到了mid,应该到[mid,r]区间找答案
如果check(mid)=false
说明在右边区间(绿色)找到了mid,应该到[l,mid-1]区间找答案
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)l=mid;
else r=mid-1;
}
步骤为:
先写一个check函数
判定在check的情况下(true和false的情况下),如何更新区间。
在check(m)==true的分支下是:
根据是l-mid还是r=mid判断到底是红色方法还是绿色方法
l=mid的情况, mid+1,中间点的更新方式是m=(l+r+1)/2
r=mid的情况,mid不用+1,中间点的更新方式是m=(l+r)/2
这种方法保证了:
二分问题一定有解,通过二分判断出的性质导出原问题可能会无解。
例:check为>=t的l,r
返回第一个位置
int search(int t,int l,int r){
while(l<r){
int mid=(l+r)>>1;
if(num[mid]>=t)r=mid;
else l=mid+1;
}
printf("%d %d\n",l,r);
}
结果为:
例:check为<=t的l,r
返回最后一个位置
int searchr(int t,int l,int r){
while(l<r){
int mid=(l+r+1)>>1;
if(num[mid]<=t)l=mid;
else r=mid-1;
}
printf("%d %d\n",l,r);
}
最终返回结果l=r
#include <iostream>
using namespace std;
const int N=1e6;
int num[N];
int searchl(int t,int l,int r){
while(l<r){
int mid=(l+r)>>1;
if(num[mid]>=t)r=mid;
else l=mid+1;
}
if(num[l]!=t)return -1;
else return l;
}
int searchr(int t,int l,int r){
while(l<r){
int mid=(l+r+1)>>1;
if(num[mid]<=t)l=mid;
else r=mid-1;
}
if(num[l]!=t)return -1;
else return l;
}
int main(){
int n,q;
scanf("%d%d",&n,&q);
for(int i=0;i<n;i++){
scanf("%d",&num[i]);
}
for(int i=0;i<q;i++){
int t;
scanf("%d",&t);
int l=searchl(t,0,n-1);
int r=searchr(t,0,n-1);
if(l==-1||r==-1)printf("-1 -1\n");
else printf("%d %d\n",l,r);
}
return 0;
}
相对于整数二分没有边界问题,很好写
while(r-l<1e-6){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid;
}
for(int i=0;i<100;i++){
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid;
}
注意范围取值
当x^3=0.001 x=0.1
不能取[-x,x]作为区间,取max(1,x)
#include <iostream>
#include <math.h>
using namespace std;
double search(double x,double l,double r){
while(r-l>=1e-7){
double mid=(l+r)/2.0;
if(mid*mid*mid>=x)r=mid;
else l=mid;
}
return l;
}
int main(){
double x;
scanf("%lf",&x);
double l=min(-1.0,x);
double r=max(1.0,x);
double ans=search(x,l,r);
printf("%.6lf",ans);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。