文章目录
适用于有序查找,时间复杂度 O ( l o g n ) O(logn) O(logn)
核心算法
非递归版本
int BinarySearch1(int a[], int value, int n){
int low=0,high=n-1,mid;
while (low<=high){ // 终止条件 low>high
mid=(low+high)/2;
if(a[mid]==value) // 判断是否找到,可换为其他语句
return mid;
else if(a[mid]>value)
high=mid-1; // 区间中值在目标值右侧,故选择左半边,变更右边界
else if(a[mid]<value)
low=mid+1; // 区间中值在目标值左侧,故选择右半边,变更左边界
}
return -1; // 没找到
}
递归版本
int BinarySerch2(int a[], int value, int low, int high){
if(low>high) // 终止条件 low>high
return -1; // 没找到
int mid=low+(high-low)/2;
if(a[mid]==value) // 判断是否找到,可换为其他语句
return mid;
else if(a[mid]>value) // 区间中值在目标值右侧,故选择左半边,变更右边界
return BinarySerch2(a, value, low, mid-1);
else if(a[mid]<value) // 区间中值在目标值左侧,故选择右半边,变更左边界
return BinarySerch2(a, value, mid+1,high);
}
STL中的二分查找函数
lower_bound(start, end, value, compare)
upper_bound(start, end, value, compare)
binary_search(start, end, value,copmare)
lower_bound
的作用是在不减的数组中进行二分检索,找到大于等于value
的第一个地址,不存在则返回地址end
upper_bound
的作用是在不减的数组中进行二分检索,找到大于value
的第一个地址,不存在则返回地址end
binary_search
的作用是在不减的数组中进行二分检索,判断value
在数组中是否存在,存在则返回ture
,不存在则返回false
如在数组{1,2,2,2,3}
中,取value=2
,则:
-
lower_bound
返回的地址是第一个2
的地址 -
upper_bound
返回的地址是**3
的地址**
参数解释
start
参与查找的数组首地址,一般为数组名
end
参与查找的数组尾地址+1,一般为数组名+数组长度
value
目标值
compare
自定义的查找规则(比较函数),默认为上述规则。
对于递减数列,设置compare
参数为greater<type>()
,可以实现查找“小于等于value
”和“小于value
”的功能,如在数组{3,2,2,2,1}
中,取value=2
,则:
-
lower_bound(start, end, value, greater<int>())
返回第一个2
的地址 -
upper_bound(start, end, value, greater<int>())
返回**1
的地址**
使用
由于函数返回的是地址,一般通过减去数组首地址的方式来获取目标的下标,如下:
int loc=lower_bound(a, a+len, value)-a; // 得到value对应的下标
例题
POJ-2456 Aggressive cows
中文版题目地址:天鹅棚
在中国传媒大学的钢琴湖里有 C C C只天鹅,XH0822为它们建造了一座包括 N N N个隔间的天鹅棚,分别在坐标轴上的 x 1 , ⋯ , x N x_1,\cdots ,x_N x1,⋯,xN位置。但这些天鹅都彼此看不惯对方,为了防止他们互相伤害,所以不能把几只天鹅放在一个隔间里,而且还应该使两只天鹅之间的最小距离尽可能的大。可XH0822思考了好久,都不知道这个最大的最小距离是多少,你能不能帮帮他呢?
数据范围: 2 ≤ N ≤ 100000 , 0 ≤ x i ≤ 1 0 9 , 2 ≤ C ≤ N 2\leq N \leq 100000, 0 \leq x_i \leq 10^9, 2 \leq C \leq N 2≤N≤100000,0≤xi≤109,2≤C≤N
输入
有多组测试数据,以EOF结束。
第一行包含两个整数
N
N
N和
C
C
C
后面接着有
N
N
N行,分别表示
x
i
x_i
xi的位置。(因为输入流可能很多,建议用scanf
读取数据)
输出
每组测试数据输出一个整数,即题目中所说的最大的最小值。
输入样例
5 3
1
2
8
4
9
输出样例
3
参考思路及代码
二分枚举所有可能的距离 d d d:
- 距离的范围应为 0 ≤ d ≤ 所有隔间中距离最远的两个之间的距离 0 \leq d \leq \text{所有隔间中距离最远的两个之间的距离} 0≤d≤所有隔间中距离最远的两个之间的距离——明确区间的原始上下限
- 对于每个
d
d
d,计算此时可以放鹅的房间数
n
u
m
num
num,并与题中要求的
C
C
C比较,如果
num>=C
,则说明当前的 d d d是满足条件的,我们去找有没有更大的 d d d也满足条件,即变更区间下限low=mid+1
,反之则要缩小距离再次尝试,即变更区间上限high=mid-1
——确定判断规则 - 题目中给出的数组 x x x是无序的,需要先排序,以便枚举时的验证
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn=100020;
int x[maxn];
int C,N;
bool isEnough(int distence){
int num=1,separate_loc=0;
for(int i=1;i<N;i++)
if(x[i]>=x[separate_loc]+distence){
num++;
separate_loc=i;
}
if(num>=C)return 1;
return 0;
}
int BinarySearch(){
int low=0,high=x[N-1]-x[0],mid;
while (low<=high){
mid=(low+high)/2;
if(isEnough(mid))low=mid+1;
else high=mid-1;
}
//return low-1;
return high;
}
int main(){
cin>>N>>C;
for(int i=0;i<N;i++)
scanf("%d",&x[i]);
sort(x,x+N);
printf("%d",BinarySearch());
return 0;
}