二分法

二分

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

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

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

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

只须要经过不断的二分就能够找到零点ui

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

二分查找

二分查找:是经过二分的方法来查找code

  • 好比在一个升序序列查找一个数是否存在
    假设一个升序
    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

codehtm

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("不存在");

二分答案

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

因此只有当答案具备单调性的时候能够进行二分blog

并且须要能找出答案的范围排序

最后就是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.经过二分排除非答案区间,在可能的答案种继续二分

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

相关文章
相关标签/搜索