部分转载自: https://www.cnblogs.com/whywhy/p/4886641.html
二分:
二分,顾名思义,就是把一个分成两个,呃,先来一个例子,现在有一个递增序列 a(1),a(2) ......a(n),让你查找x在不在这个序列里面,在的话在哪个位置,最简单的做法就是对这个序列进行一次遍历,直到找到为止,但这么做显然太麻烦了,给你一个1e9的数组,x又恰巧在最后一位,就需要循环1e9次,所以就需要二分啦,你先找到a (n/2) ,如果x>=a (n/2) ,那x就在a (n/2)到a(n)这一段,否则就在a(1) 到a (n/2) ,如果在a(1) 到a (n/2),那就在找a (n/4),比较和x的大小,就这么依次找下去。。。这样每次把区间变成原来的一半,那么就是 logN 级别的时间复杂度,对于长度 n=100000 的序列,只需要不到20次就能判断x了。
上个模板:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include <cstring>
#include<map>
using namespace std;
// 查找A数组是否存在x。
int Find(int A[],int N,int x)
{
int L=0,R=N-1,M;
while(R>L)
{
M=(L+R)/2;
if(A[M]==x) return L;
else if(A[M]>x) R=M-1;
else L=M+1;
}
if(A[L]==x) return L;
return 0;
}
int main()
{
int n,a[5000],x,i;
cin>>n;
for(i=0;i<n;i++)
cin>>a[i];
cin>>x;
cout<<Find(a,n,x)<<endl;
return 0;
}
通俗的说,其实二分是针对一个单调函数,在这个函数的一个区间中查找,每次取区间的中点去判断,然后根据大小把区间变成原来的一半。。。然后一直这样下去就好。
果说二分针对的是单调函数,那么三分针对的是双调函数。也就是下面这样的函数。
三分是求这样先增后减或者是先减后增的函数的极值的。
具体步骤就是:对于区间 (L,R),先求出 1/3 处的 M1 和 2/3 处的 M2,然后比较 M1 和 M2 处的大小,如果 M1 处的值大于 M2 处的值,那么极值一定在(M1,R)这个区间范围内,否则一定在 (L,M2)这个范围内。
因为如果 M1处大于M2处的话,M1不可能在极值点的右边。。。所以。。。就是这样了。。。每次变成原来区间的2/3大小。。。
double型的三分模板
const double eps=1e-10;
double calc(double n)
{
return ; //根据题目条件计算
}
double solve(double L,double R)
{
double M,RM;
while(L+eps<p)
{
M=(L+R)/2;
RM=(M+R)/2;
if(calc(M)<calc(RM))
R=RM;
else
L=M;
}
return L;
}