二分法c++
什么是二分法:
百度百科是这样说的:
基本思想:假设数据是按升序排序的,对于给定值x,从序列的中间位置开始比较,如果当前位置值等于x,则查找成功;若x小于当前位置值,则在数列的前半段中查找;若x大于当前位置值则在数列的后半段中继续查找,直到找到为止。
注意:数据必须是排好序的!
详细解释:二分查找
看一下流程图:
再举一个栗子:
Aggressive cows POJ - 2456
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000).
His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?
Input
* Line 1: Two space-separated integers: N and C* Lines 2..N+1: Line i+1 contains an integer stall location, xi
Output
* Line 1: One integer: the largest minimum distanceSample Input
5 31
2
8
4
9
Sample Output
3Hint
OUTPUT DETAILS:FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.
Huge input data,scanf is recommended.
分析:贪心+二分:注意小心TLE:
将本代码改用c++就会TLE!!!!
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100010];
int n,c;
bool judge(int x) {
int cnt=1;
int tmp=a[0];
for(int i=1; i<n; i++) {
if(a[i]-tmp>=x) {
cnt++;
tmp=a[i];
if(cnt>=c)
return true;
}
}
return false;
}
int main() {
while(scanf("%d%d",&n,&c)!=EOF) {
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
sort(a,a+n);
int l=0,r=a[n-1]-a[0],mid;
while(l<=r) {
mid=(l+r)/2;
if(judge(mid))
l=mid+1;
else
r=mid-1;
}
printf("%d\n",l-1);
}
return 0;
}
思路比较简单:关键在于:
- 对于二分法的停止条件:
- 对于二分法更新L、R的值区间开闭的问题
- 对于最后输出是L-1而不是L的问题;
- 使用二分查找的时候需要明确查找对象!
- 本题中查找的是宽度!也就是数组的值而不是位置;
- l相当于做区间左边界,r相当于区间的右边界,m是中间的分界线:一般是:(l+r)/2;
- 使用循环缩小范围;缩小范围的过程是更新左右边界的过程;
- 循环停止的条件:左右边界重合的时候,或者左边界大于右边界的时候;
- 这是最小值最大化问题:先对间隔编号从小到大排序,则最大的距离不会超过两端
- 两头牛之间的差值,最小值为零。通过二分枚举:设当前最小值为x,如果判断出最西欧啊差值为x是
- 可以放下c头牛,说明当前的x有点小,x++在判断;若放不下,说明当前的x太大了,就让x--后在进行判断。
- 知道求出一个最大的x就是最终答案。
并不是所有时候的二分查找的循环停止条件都一致:注意要因题而异!不要思维僵化。
重大发现:是否取等与l更新边界值的方式有关!如果l=mid+1需要取等;如果是l=mid不需要取等!