//二分法 #include<iostream> using namespace std; const int N = 100010; int n,k; int h[N],w[N]; bool check(int x) { int res=0; for(int i = 1;i <= n;i++) { res += (h[i]/x)*(w[i]/x); } if(res>=k) { return true; } return false; } int main() { int mid; scanf("%d %d",&n,&k); for(int i = 1;i <= n;i++) { scanf("%d %d",&h[i],&w[i]); } int l = 1,r = 1e5,max = 0; while(l <= r) { mid = (l+r)/2; if(check(mid)) { max = mid; l = mid+1; } else{ r = mid - 1; } } printf("%d",max); }
针对小明分巧克力
一、思路分析:
为了合理分巧克力,我们需要找到一个合理的数使得每个小孩都能分到相同的巧克力,自然而然,我们就想起了查找,但是暴力查找所耗费时间太多,因此采用2分查找!
二、二分查找的格式
关于左闭右闭,[left,right]
int binarySearch(int arr[], int size, int target)
{
int left = 0;
int right = size - 1;
while (left <= right)
{
int mid = (left + right) / 2;
// int mid = left + (right - left) / 2;
if (arr[mid] < target)
{
left = mid + 1;
}
else if (arr[mid] > target)
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
关于左闭右开,[left,right)
int search(int nums[], int size, int target)
{
int left = 0;
int right = size; //定义target在左闭右开的区间里,即[left, right)
while (left < right) { //因为left = right的时候,在[left, right)区间上无意义
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle; //target 在左区间,在[left, middle)中
} else if (nums[middle] < target) {
left = middle + 1;
} else {
return middle;
}
}
// 没找到就返回-1
return -1;
}
两者区别:
1.left<=right,right = mid-1,right = size-1(左闭右闭)&&left<right,right = mid,right = size(左闭右开)
首先,针对左闭右闭,给出例子[1,1],可知讨论left<=right是有意义的;
但是由于right取实数,那么根据数组的规则(为防止越界行为出现),就要对right = size-1,mid也为实数,在计算中,也将mid包含进去进行判断,因此在查找的后续一半中,就不用再将mid加入循环了。
其次,针对左闭右开,给出例子[1,1),可知讨论left<=right是无意义的;
但是由于right也取不到,size无后顾之忧,可直接进行right = size!
三、具体代码流程(此处以左闭右闭为例):
将left设置为一个很小的数,比如1;right设置为一个很大的数一般为1e5(可以更大这不重要,不过是增加复杂度而已)等。
接着设置一个while循环,满足l<=r(以mid为界),要满足该条件;
1 | 2 | 4 | 7 | 9 |
0 | 1 | 2 | 3 | 4 |
mid = (0+4) / 2 =2
1 | 2 | 4 | 7 | 9 | 11 |
0 | 1 | 2 | 3 | 4 | 5 |
mid = (0+5) / 2 = 2
再在循环体中,求出mid = (left+right)/2(此处可以不用管奇偶性)
接着在进行判断,if(nums[mid]>target)(判断条件可根据题目自行进行修改)则target位于数列左半边,将right修改为mid-1;
else if(nums[i]<target),位于数列右半边,对left进行修改,left = mid+1;
else return mid(恰好位于mid上的target)
找不到的话返回-1;