一、认识
二分又分为二分查找和二分答案,它们的时间复杂度为O(二分查找的次数*每次查找的复杂度)。
1.二分查找
二分查找其实就是让你在一大堆数中折半寻找一个数
2.二分答案
二分答案是指折半列举一个答案是否符合题目要求
某一蒟蒻():哎?这咋回事?
另一蒟蒻:来,直接上题来理解
二、学习
1.二分查找
给定一个n,再给n个数和一个要查找的数,输出这个数的下标,用二分查找来实现:
输入:
5
75 324 2 61 23
23
输出:
5
二分一定要记住对半查找
这是无序的一个数组,所以需要先sort排序,而且要输出下标,但是sort排序后计算机无法记住这个数原来在哪,所以要用结构体记录这个数原来的下标,如下:
#include <bits/stdc++.h>
using namespace std;
int n,m;
struct SHU{
int a,bianhao;
}shu[105];
bool cmp(SHU x,SHU y){
return x.a<y.a; //从小到大
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>shu[i].a;
shu[i].bianhao=i;
}
cin>>m;
sort(shu+1,shu+n+1,cmp);
return 0;
}
如果没学过sort排序,看这篇文章:C++系统函数sort运用https://blog.csdn.net/ljmhxs/article/details/120090253https://blog.csdn.net/ljmhxs/article/details/120090253
这样就排好序了,接下来就是二分查找了(折半查找!):
#include <bits/stdc++.h>
using namespace std;
int n,m;
struct SHU{
int a,bianhao;
}shu[105];
bool cmp(SHU x,SHU y){
return x.a<y.a;
}
bool judge(int x){
return shu[x].a > m; //看不懂可以看下面
}
/*
bool judge(int x){
if(shu[x].a > m) return 1; //如果中间数比 m 大,返回1
else return 0;
}
*/
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>shu[i].a;
shu[i].bianhao=i;
}
cin>>m;
sort(shu+1,shu+n+1,cmp);
int l=1,r=n,mid; // l 指左边,r 指右边,mid 指中间
while(l<r){
mid=(l+r)/2; //折半,看中间与要找的数 m 的关系
if(judge(mid)){ //判断关系
l=mid+1; //如果发现中间比要找的数大了 ,那就在右边找
}else{
r=mid; //否则往左边找
}
}
cout<<shu[mid].bianhao; //输出编号即可
return 0;
}
这就是二分查找
2.二分答案
一个整数n和一个整数k,给出n个树的高度,要求找出一个高度,使得这n个数的高度减去这个高度的结果正好为k.
输入
5 100
90 95 60 70 85
输出
60
二分答案一定要对半找
某杠精:总感觉这句话在哪里见过?
某作者:我感觉你感觉的没错!
这句话是极为重要的!!学习二分一定要记住!
二分首先要找到查找的边界值,这道题的边界值是这些树的最高的和最低的,所以输入为:
(边界值其实怎样都可以,比如这道题,也可以是1和1000,不影响真正结果,只要右边界比答案大就可以了)
#include <bits/stdc++.h>
using namespace std;
int n,k,a[1000005],maxx,minn;
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
maxx=max(maxx,a[i]); //最大
minn=min(minn,a[i]); //最小
}
int l=minn,r=maxx,mid;
while(l<=r){
mid=(l+r)>>1; //相等于mid=(l+r)/2;
}
//二分
return 0;
}
接下来就是二分答案,折半列举答案后看此答案是否符合题意:(看代码!)
#include <bits/stdc++.h>
using namespace std;
int n,k,a[1000005],maxx,minn;
int judge(int x){ //3种情况返回值类型为int
int sum=0; //累加器
for(int i=1;i<=n;i++)
if(a[i]-x>=0) //防止累加到负数,影响最终结果
sum+=a[i]-x; //累加 减去折半查找到的答案
if(sum>k) return 1; //累加后比k大,返回1
else if(sum==k) return 0; //累加后正好等于,返回0,回去输出
else if(sum<k) return 2; //累加后小于k,返回1
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
maxx=max(maxx,a[i]);
minn=min(minn,a[i]);
}
//输入
int l=minn,r=maxx,mid;
while(l<=r){
mid=(l+r)>>1;
int f=judge(mid);
if(f==1){ //累加后比k大
if(judge(mid+1)==2){ //如果没有正好的答案,只有超出一点的
//检查答案+1是否比k小,如果小的话
cout<<mid; //输出答案
return 0;
}
l=mid-1; //左边界找右边,一定要-1,因为要把mid包括进去算
}else if(f==0){
cout<<mid; //正好就直接输出
return 0;
}else if(f==2){ //累加后比k小
r=mid+1; //右边界找左边,一定要+1,因为要把mid包括进去算
}
}
cout<<mid;
//二分答案
return 0;
}
所以你似乎掌握了亿点二分的知识呢!还是不会的同学还是得多刷题
such as(题解什么的自己找)
A-B 数对https://www.luogu.com.cn/problem/P1102https://www.luogu.com.cn/problem/P1102
眼红的Medusahttps://www.luogu.com.cn/problem/P1571https://www.luogu.com.cn/problem/P1571
[NOIP2001 提高组] 一元三次方程求解https://www.luogu.com.cn/problem/P1024https://www.luogu.com.cn/problem/P1024
进击的奶牛https://www.luogu.com.cn/problem/P1824https://www.luogu.com.cn/problem/P1824
木材加工https://www.luogu.com.cn/problem/P2440https://www.luogu.com.cn/problem/P2440
[NOIP2015 提高组] 跳石头https://www.luogu.com.cn/problem/P2678https://www.luogu.com.cn/problem/P2678
【例7.4】 循环比赛日程表http://ybt.ssoier.cn:8088/problem_show.php?pid=1325http://ybt.ssoier.cn:8088/problem_show.php?pid=1325网线主管http://ybt.ssoier.cn:8088/problem_show.php?pid=1242http://ybt.ssoier.cn:8088/problem_show.php?pid=1242
查找最接近的元素http://ybt.ssoier.cn:8088/problem_show.php?pid=1240http://ybt.ssoier.cn:8088/problem_show.php?pid=1240
强烈建议做做这些题!
不会的同学私信我!
点赞你要亮,关注干得漂亮
不关注点赞你就别走(好像我也留不住)
那就要个点赞吧(要求不大吧)