二分法(Binary Search)是一种高效的搜索算法,适用于已排序的数组。它的基本思想是在每一步中,将待搜索区间一分为二,并确定目标值可能存在的位置。然后根据目标值与中间元素的大小关系,决定舍弃哪一半的区间,从而将搜索范围缩小一半。重复这个过程,直到找到目标值或者确定目标值不存在为止。
难点:
1.while()的循环条件能否取等
如果是左闭右闭区间可以取等,有一边是开区间则不能取等
2.right取mid还是mid-1
- 如果是右闭的区间,值是可以取到的,既然mid已经大于target, 没必要继续加到区间上,所以需要right移动到mid的前一个位置
- //右开说明取不到mid,直接right取到mid
- 对于左闭右闭区间 [left,right]
vector<int> arr(1000);
int left = 0;
int right = a.size() - 1;
int target = 1;
while (left <= right) {//左闭右闭区间可以取等号
int mid = (right - left) / 2;
if (arr[mid] > target) {
//由于是右闭的区间,值是可以取到的,既然mid已经大于target,
//没必要继续加到区间上,所以需要right移动到mid的前一个位置
right = mid - 1;
}else if (arr[mid] < target) {
left = mid + 1;
}else {
return mid;
}
}
return -1;
防止越界写法:int mid = left + (right - left) / 2;
- 对于左闭右开区间 [left,right)
//左闭右开区间不可以取等,如[1,1)就是一个不合法的区间,既包含1又不包含1.
int solve() {
vector<int> a(1000);
int left = 0;
int right = a.size();//由于右边不包含边界,所以right=a.size()
int target = 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (a[mid] > target) {
//右开说明取不到mid,直接right取到mid
right = mid;
}
else if (a[mid] < target) {
//左闭说明能取到,此时已经明确a[mid]不会再等于target
//所以取到mid的下一位
left = mid + 1;
}
else {
return mid;
}
}
return -1;
}
二分法的妙用
P8647 [蓝桥杯 2017 省 AB] 分巧克力 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
巧妙地使用了二分法来解决这个问题,根据数据的范围来解决该问题,大大降低了效率。
其基本思路是先确定二分的范围为 [1, 10^5],然后通过 check 函数来判断当前的 mid 是否满足条件。如果满足条件,则将左边界 l 更新为 mid,否则将右边界 r 更新为 mid-1。最终得到的 l 即为所求的最大边长。
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N = 1e5+10;
int h[N],w[N],n,k;
bool check(int mid){
int res = 0;
for(int i=0;i<n;i++){
res += (h[i]/mid)*(w[i]/mid);
if(res>=k) return true;
}
return false;
}
int main() {
cin>>n>>k;
for(int i=0;i<n;i++) scanf("%d%d",&h[i],&w[i]);
int l=1,r=1e5;
while(l<r){
int mid = l+r+1>>1;
if(check(mid)) l = mid;
else r = mid-1;
}
cout<<l<<endl;
return 0;
}