• 二分与三分


    其实二分,三分与分治的思想差不多,都是对一个问题的分段操作(前提为有序)

                                    ——QwQ

    二分

    二分法,在一个单调有序的集合或函数中查找一个解,每次分为左右两部分,判断解在哪个部分中并调整上下界,直到找到目标元素,每次二分后都将舍弃一半的查找空间,因此效率很高。

    例如,对于在实数区间[L,R]内递增的连续函数f(x),求[L,R]内f(x)的零点J。J称为(x)在[L,R]内的零点,当且仅当满足:

      任意L≤x<J,f(x)<0

      任意J<x≤R,f(x)>0

        f(J)=0

    二分法的思想是不断将待求解区间平均分成两份,根据求解区间中点的情况来确定目标元素所在的区间,这样就把解的范围缩小了一半

    设当前求解区间为 [ l , r ] , 它的中点为mid =( l+r )/2则有

    若f(m)<0,则J∈[m,r];

    若f(m)>0,则J∈[l,m];

    若f(m)=0,则J=m

    那么,二分算法的复杂度为O(二分次数×单次判定复杂度)

    1.整数定义域上的二分

    int Erfen(int l,int r)
    {
        int l=1,r=n,ans;
        while(l<=r)
        {
            int mid=(l+r)/2;
            //int mid=l+(r-l)/2;
            if(check(mid))  
            {
                ans=mid;
                l=mid+1;
            }
            else r=mid-1;
        }
        return ans;
    }

    2.实数定义域上的二分

    int Erfen(double l,double r)
    {
        double eps=0.001; 
        while(fabs(r-l)>eps)
        {
            double mid=(l+r)/2.0;
            if(check(mid))    r=mid;
            else l=mid;
        }
        return l;
    }

    常见的类型

    1.二分答案
           最小值最大(或是最大值最小)问题,这类双最值问题常常选用二分法求解,也就是确定答案后,配合贪心、DP等其他算法检验这个答案是否合理,将最优化问题转换为判定性问题。例如,将长度为n的序列a分成最多m个连续段,求所有分法中每段和的最大值的最小是多少

    2.二分查找
          用具有单调性的布尔表达式求解分界点,比如在有序数列中求数字x的排名

    3.代替三分
           有时,对于一些单峰函数,我们可以用二分导函数的方法求解函数极值,这时通常将函数的定义域定义为整数域求解比较方便,此时dx可以直接取整数1

    三分法适用于求解凸性函数的极值问题,二次函数就是一个典型的单峰函数。

    三分法与二分法一样,它会不断缩小答案所在的求解区间。二分法缩小区间利用的原理是函数的单调性,而三分法利用的则是函数的单峰性

    设当前求解的区间为 [l,r] ,令 m=1+(l+r)/3 , m=r-(l+r)/3 , 接着我们计算这两个点的函数值f(m1),f(m2)之后我们将两点中函数值更优的那个点称为好点,函数值较差的那个点称为坏点。我们可以不停缩小求解区间,直至得出近似解

    与二分一样,我们可以指定三分的次数,或是根据 r-1的值来终止

    double l=0,r=1e9;
    while(r-l>=1e-3)
    {
        double m1=l+(r-l)/3;
        double m2=r-(r-l)/3;
        if(f(m1)<f(m2)) l=m1;
        else r=m2;
    }

    这里再放几个题看看

    1433:【例题1】愤怒的牛

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=1e5+3;
    int n,m,x[N];
    inline bool check(int d){
        //以d为答案,看是否正确 
        int cow=1;
        int rgt=x[1]+d;
        for(int i=2;i<=n;i++)
        {
            if(x[i]<rgt) continue;
            //不符合跳过 
            ++cow;
            rgt=x[i]+d;
            //符合计数并更新rgt 
        }
        return cow>=m;
        //cow>=m是成立 
    }
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++) cin>>x[i];
        sort(x+1,x+1+n);
        //二分查找 
        int l=0,r=x[n]-x[1];
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid)) l=mid+1;
            else r=mid-1;
        }
        cout<<r;
        return 0;
    }    

    1434:【例题2】Best Cow Fences

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    double a[100001],b[100001],sum[100001];
    int main(){
        int N,L;
        cin>>N>>L;
        for(int i=1;i<=N;i++){
            cin>>a[i];
        }
        double eps=1e-5;
        double l=-1e-6,r=1e6;
        while(r-l>eps){//二分答案 
            double mid=(l+r)/2;
            for(int i=1;i<=N;i++) b[i]=a[i]-mid;
            for(int i=1;i<=N;i++) sum[i]=(sum[i-1]+b[i]);
            double ans=-1e10;
            double minn=1e10;
            for(int i=L;i<=N;i++){
                minn=min(minn,sum[i-L]);
                ans=max(ans,sum[i]-minn);
                //前缀和相减 
            }
            if(ans>=0) l=mid; 
            else r=mid;
        }
        cout<<int(r*1000)<<endl;
        return 0;
    }

    1435:【例题3】曲线

    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<iomanip>
    using namespace std;
    int T,test,n;
    double a[10005],b[10005],c[10005];
    double x,maxx=0,L,r,Lmid,rmid;
    double cal(double x){
        int i,j;
        double maxx=-0x7fffffff;
        for(i=1;i<=n;i++) maxx=max(maxx,a[i]*x*x+b[i]*x+c[i]);
        return maxx;
    } 
    int main(){
        int i,j;
        cin>>T;
        for(test=1;test<=T;test++){
            cin>>n;
            for(i=1;i<=n;i++) cin>>a[i]>>b[i]>>c[i];
            L=0;r=1000;
            while(L+1e-11<r){
                Lmid=L+(r-L)/3;
                rmid=r-(r-L)/3;
                if(cal(Lmid)<=cal(rmid)) r=rmid;
                else L=Lmid;
            }
            printf("%.4lf
    ",cal(L));
        }
        return 0;
    }
  • 相关阅读:
    media query 开发总结
    整屏滚动
    移动端reset样式
    中国天气网 城市代码 sql语句
    php文章tag标签的增删
    oracle的分号和斜杠/
    php 操作 oracle lob 数据2
    php 操作 oracle lob 数据
    oracle创建用户
    php进度条
  • 原文地址:https://www.cnblogs.com/gongcheng456/p/10992747.html
Copyright © 2020-2023  润新知