二分查找算法

疫情在家闲来无事,高深算法也并不着急学,想起寒假培训被二分支配的恐惧。。(基本没一道会的,只能照抄代码),于是抽了一天做做以前的二分题目,总结一下,企图掌握这高深的二分查找法。。

nefu 956 二分查找

#include 
using namespace std;
int a[1000009];
int main()
{
     
    int n;
    int k;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
     
        scanf("%d",&a[i]);
    }
    int l=1,r=n;
    while(r>l)
    {
     
        int m=(r+l)/2;
        if(a[m]<=k)l=m+1;
        else r=m;
    }
    printf("%d\n",r-1);//这题r-1,l-1,m-1都行,因为相等
    return 0;
}

nefu 1646 小清新的二分查找之旅

#include 

using namespace std;
long a[1000009];
int main()//二分查找法的模板题,要熟练
{
     
    int n,q,flag,x;
    while(scanf("%d%d",&n,&q)!=-1)
    {
     

        for(int i=1;i<=n;i++)scanf("%ld",&a[i]);
        for(int i=0;i<q;i++)
        {
     
            flag=0;
            scanf("%d",&x);
            int l=1,r=n,m;
            while(r>=l)//带入一组数据判断是否要加等号
            {
     
                m=(l+r)/2;
                if(a[m]>x)r=m-1;
                if(a[m]<x)l=m+1;
                if(a[m]==x){
     flag=1;break;}
            }
            if(flag==0)printf("YES\n");
            else printf("no\n");
        }
    }
    return 0;
}

nefu 1645 小清新的函数坐标-二分

这种实数类型的查找原理为 将x对应的y无限逼近于所要查找的那个y,是逼近,不是等于(除非数据故意给你整数),最后求出的那个x也是逼近的并不是真实的,r-l 越小,就越逼近

#include 

using namespace std;
double f(double x)
{
     
    double r=0.0001*x*x*x*x*x+0.003*x*x*x+0.5*x-3;
    return r;
}

int main()
{
     
    double y;
    while(~scanf("%lf",&y))
    {
     
        double l=-20.0,r=20.0;double m;
        while(r-l>=0.00001)
        {
     
            m=(l+r)/2;
            if(f(m)<y)l=m;
            if(f(m)>y)r=m;
            if(f(m)==y)break;//节约时间
        }
        printf("%.4lf\n",m);
    }
    return 0;
}

nefu1648 小清新切绳子-二分

两个点:1.int可能会爆,用long long
2. ;m= r - ( r - l )/2;换成m=(l+r)/2;就不行,就tle了,我也不知道为啥,记住吧。。

#include 

using namespace std;
int k,n;int a[10005];
bool judge(int len)
{
     
    long long cnt=0;
    for(int i=1;i<=n;i++)
    {
     
        cnt+=(long long)(a[i]/len);
    }
    return cnt>=k;
}

int main()
{
     
    while(~scanf("%d %d",&n,&k))
    {
     
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int l=1,r=9999999;
        int  m;
        while(r>l)
        {
     
            m= r - ( r - l )/2;
            if(judge(m))l=m;
            else r=m-1;
        }
        printf("%d\n",r);
    }
    return 0;
}

nefu1751 切绳子实数版-二分

这题的思路就是将实数变为整数,转成上面那个题的样子做

#include 

using namespace std;
int k,n;int a[10005];
bool judge(int len)
{
     
    long long cnt=0;
    for(int i=1;i<=n;i++)
    {
     
        cnt+=(long long)(a[i]/len);
    }
    return cnt>=k;
}

int main()
{
     
    while(~scanf("%d %d",&n,&k))
    {
     

        float x;
        for(int i=1;i<=n;i++){
     scanf("%f",&x);a[i]=(int)(x*1000);}
        long long l=1,r=999999999;
        long long  m;
        while(r>l)
        {
     
            m= r - ( r - l )/2;
            if(judge(m))l=m;
            else r=m-1;
        }
        double o=r*0.001;
        printf("%.2lf\n",o);
    }
    return 0;
}

*nefu1211卖古董-DP-二分

这题有难度,题目很经典

思路:以每天卖出的古董价值总和上限val为标准,以此分配每天的最大销量,若在m天内卖完,尝试压缩val标准,若m天内卖不完,说明val标准太低,尝试放宽标准,二分法求val的最大值,(理想状态是每天卖出 sum/ m 的价值,可以以此为下边界,上边界即为价值总和,即一天内全卖完)

#include 

using namespace std;
int k,n;int a[100005];
bool judge(int len)
{
     
    int leng=len;
    int sum=1;
    for(int i=1;i<=n;i++)
    {
     
        if(len<a[i])return false;
        if(leng>=a[i])leng-=a[i];
        else {
     sum++;leng=len-a[i];}
    }
    return sum<=k;
}

int main()
{
     
    int t;
    cin>>t;
    while(t--)
    {
     
        scanf("%d %d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        int l=1,r=999999,m;
        while(r>l)
        {
     
            m=l+(r-l)/2;
            if(judge(m))r=m;
            else l=m+1;
        }
        printf("%d\n",r);
    }
    return 0;
}

你可能感兴趣的:(算法,二分法,acm竞赛,oj系统)