二分法

二分

二分顾名思义
其实就不断的把东西分为两半
二分自古就有

  • 一尺之棰,日取其半,万世不竭 -----《庄子·杂篇·天下》

二分在数学中,也有应用,例如零点存在性定理

\(设y=f(x) 如果f(x)在 [a,b]上连续 且 f(a)*f(b)<0 则[a,b]之间存在零点\)

只需要通过不断的二分就可以找到零点

今天主要介绍两种二分的应用

二分查找

二分查找:是通过二分的方法来查找

  • 比如在一个升序序列查找一个数是否存在
    假设一个升序
    1,5,8,9,11,20,33
    我们要查找一个数为1
    先将1与中间数9相比较,1比9小,那么1为一定在以9为分割点,分成的两个区间的左区间[1,5,8]
    再将1与区间[1,5,8]的中间数5相比较,1小于5,那么一定在以5为分割点,分成两个区间的左区间[1]
    最后找到1

code

int l=1,r=7,mid;
int s[9]={0,1,5,8,9,11,20,33};
int k=1//我们要查找的数 
while(l<=r){
	mid=(l+r)>>1;//等价于(l+r)>>1
	if(k<=s[mid]) r=mid-1;
	else l=mid+1; 
}
if(s[l]==k) printf("存在");
else printf("不存在"); 

二分答案

二分答案,二分的对象是答案,但二分的对象有具有单调性

所以只有当答案具有单调性的时候可以进行二分

而且需要能找出答案的范围

最后就是check(答案),判断最终答案在左区间还是右区间最终得到答案

例题选讲

进击的奶牛

一般看见这种最大值的最小值也有可能用二分答案

首先我们需要确定具有单调性

求得相邻两头牛最近距离得最大值,因为距离嘛,要么长要么短,短的变到长,具有单调性实锤

那范围了?
最小值:可以为两个隔间的最小距离
最大值:两个相距最远得隔间得差
很容易看出来
(稍微讲下原因,懂得同学就往后看把

  • 原因
    最小值应该容易理解吧,如果最小值比相邻两个隔间最小值还小,那根本不存在其他隔间能放牛
    比如两头牛
    三个隔间坐标
    1,3,9
    最小值为2,如果此时你设最小值为1,那根本不存在这样一个答案
    既然是答案,那么一定具有答案的性质,能有解

借用刚刚的例子最大值为8
答案还能取9吗?显然不能,因你取9的话,此时也不存在两个隔间相距离为9

check环节
举栗
1,2,4,8,9

最小值:1
最大值:8
\(ans∈[1,8]\)
取中间值 4
从第1个隔间开始放1头牛,找到
下1个隔间>=4四的隔间放第2头牛,即在第4个隔间放
结果你会发现下1头牛,没有位置可放了,这说明什么?

这说明最近距离太大了,并不满题意(好好理解一下

则答案一定在[1,3]之间(因为如果距离>=4,是不是能放的牛可能更少

取中间值 2
从第1个隔间开始放第1头🐂
那么第2头🐂则会放在第3个隔间
第3头🐂会放在第5个隔间
放完了所有🐂,也满足题意
那么这个是不是最终答案了?
(还有待观察

好既然最近距离为2时一定满足其条件,那么距离比2小的也同样满足(这里需要思考一下,其实也挺简单~

那比2大的距离可不可能满足条件?
(**有可能**,此时距离2满足题意只能说明距离2确实是一种答案,但注意此时[2,4]之间也可能存在答案,也许多放一格距离也可能满足题意)

此时取[2,3]中间值3
从第1个隔间开始放第1头🐂
那么第2头🐂则会放在第3个隔间
第3头🐂会放在第5个隔间
放完了所有🐂,也满足题意

此时区间为[3]
此时就找到最近距离的最大值

回放一遍我们模拟过程
判断其答案是否满足题意,排除不满足的区间,留下满足的区间,最终找到最终答案

  • code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

using namespace std;
int n,c;const int maxn=1e5+10;
int m[maxn];
int st[maxn],top=1;
long long l=1e9,r;
bool check(long long mid){
	int tot=1;st[top]=m[1];top=1;
	for(int i=2;i<=n;++i)
		if(m[i]-st[top]>=mid) ++tot,st[++top]=m[i];
	return tot>=c;
}
int main(){
	cin>>n>>c;
	for(int i=1;i<=n;++i){
		cin>>m[i];
		if(i>=2) l=min((long long)m[i]-m[i-1],l); 
	}
	sort(m+1,m+1+n);r=m[n]-m[1];
	long long mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid)) l=mid+1;
		else r=mid-1;
	}cout<<r<<endl;return 0;
}

总结

二分查找
查找的关键字一定具有单调性
(如果二分对象无序,那么需要排序,排序的学习笔记

二分答案

  1. 答案具有单调性
    2.找出答案的上下界(也就是最小值及最大值)
    3.通过二分排除非答案区间,在可能的答案种继续二分

其实二分本质也是枚举,在一种特殊具有单调性序列或其他具有单调性东西的一种高效枚举

posted @ 2021-08-06 16:05  归游  阅读(525)  评论(0编辑  收藏  举报