二分的思想很简单,就是对半砍,但是会有很多边界问题让人头大,这里我们先来看一下模板代码(取自AcWing)
bool check(int x){
//检查x是否满足某种性质
}
//区间[l,r]被划分为[l,mid]和[mid+1,r]时使用;
int bsearch_1(int l,int r){
while(l<r){
int mid = l+r >> 1;
if(check(mid)) r = mid;//check判断mid是否满足性质
else l = mid + 1;
}
return l;
}
//区间[l,r]被划分为[l,mid-1]和[mid,r]时使用;
int bsearch_2(int l,int r){
while(l<r){
int mid = l+r+1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
浮点数二分模板:(取自AcWing)
bool check{
//判断条件
}
double bsearch_3(double l,double r){
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while(r-l>eps){
double mid = (l+r)/2;
if(check()) l = mid;
else r = mid;
}
return l;
}
我们以例题来看吧:
https://www.acwing.com/problem/content/791/
这个题不是很难,就是求一个数出现的区间,已告诉是升序,所以就不用排序了,直接套模板二分
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+9;
int q[N],m,n,x;
bool check1(int mid){
if(q[mid]>=x) return true;
else return false;
}
bool check2(int mid){
if(q[mid]<=x) return true;
else return false;
}
int main(){
cin >> n >> m;
for(int i=0;i<n;i++){
scanf("%d",&q[i]);
}
while(m--){
scanf("%d",&x);
int l=0,r=n-1;
while(l<r){
int mid = l+r >> 1;
if(check1(mid)) r = mid;
else l = mid+1;
}
if(q[l]!=x) printf("-1 -1\n");
else{
printf("%d ",l);
int l=0,r=n-1;
while(l<r){
int mid = l+r+1 >> 1;
if(check2(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l);
}
}
return 0;
}
接下来就是浮点数二分,浮点数二分要比整数二分简单很多,因为没有那些头疼的边界问题。
https://www.acwing.com/problem/content/792/
#include<bits/stdc++.h>
using namespace std;
double n;
int main(){
cin >> n;
double l = -10000,r = 10000;
while(r-l>=1e-8){
double mid = (l+r)/2;
if(mid*mid*mid>=n) r = mid;
else l = mid;
}
printf("%6f\n",l);
}