二分and三分

 部分转载自:   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;
}
原文地址:https://www.cnblogs.com/jk17211764/p/9677357.html