二分答案 是 c++ 之中一个简单而重要的算法,每一个 OIer 必备的基础算法,你知道它究竟是什么吗?
目录
一、简介
1.定义
二分答案是一种二分搜索,二分搜索(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是一种在有序数组中查找某一特定元素的搜索算法。那么二分答案顾名思义即是在一个特定区间内搜索答案的算法,二分答案一般求一个最大值的最小值,或最小值的最大值,比如求小于 2 的最大正整数(这种题当然不必二分答案)。且有一个最大边界值和最小边界值(前面的例子若去掉“正”字,将无法二分答案,因为小于2的整数集合是无限集合)。二分答案要求必须有单调性,一会符合条件,一会不符合只能枚举。
2.时间复杂度
二分答案,顾名思义采用了分治思想,不断缩小搜索范围,最后求出答案,所以时间复杂度自然是对数阶的,由于是二分,所以时间复杂度是 O(k log n) 的,k 是什么,请往下看······
二、核心代码
int l = 1,r = n,ans; // l 是最小值,r 是最大值,ans 是答案。
while(l<=r)
{
int mid = (l + r) / 2; // mid 是最大范围和最小范围的中间值。
if(check(mid)) // 检查 mid 是否符合条件。
{
r = mid - 1;
ans = mid;
// mid 是符合条件的,继续搜索有没有比它还小的符合条件的值。
}
else l = mid + 1;
// mid 不符合条件,所以 mid 和 mid 以下的值都不行。
}
cout << ans;
仔细读几遍代码,可以发现,k 就是 check 的时间复杂度啦!
三、例题
1.跳石头
1.题目描述
一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
2.解法
自然是二分若求最短跳跃距离啦,但“最短跳跃距离尽可能长”的话 while 循环里的代码就不能像刚才那样了,恰恰相反:
int l = 1,r = n,ans;
while(l<=r)
{
int mid = (l + r) / 2;
if(check(mid))
{
l = mid + 1;
ans = mid;
}
else r = mid - 1;
}
cout << ans;
check 函数里遍历所有石头,若两石头之间距离不够长就扩大,最后若扩大次数小于等于 m 返回 true 。
bool check(int x)
{
int ans = 0,temp = a[0];
for(int i = 1;i <= n + 1;i ++){
if(a[i] - temp < s){
ans ++;
}
else{
temp = a[i];
}
}
if(ans > m) return false;
return true;
}
为什么 i 要遍历到 n+1 ,因为“(不含起点和终点的岩石)”,说明重点会有石头。为什么 “return true” 前面不用加 “else” 因为 “return false” 函数就结束了。
2.进击的奶牛
1.题目描述
Farmer John 建造了一个有 N 个隔间的牛棚,这些隔间分布在一条直线上。
他的 C 头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?
2.思路
1.一定要排序 !!!
2.二分最大距离
你学会了吗?