训练第四周之二分查找

二分法

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。一般在单调函数中用得比较多,直接看题吧。

1、Pie-hdu1969

思路:

这里直接查找所求,也就是每个人能得到的最大pie,然后条件是right-left>1e-6,这种对精度要求比较高的大都可以这样写

代码:

#include<cstdio>
#include<cstring>
#include<math.h>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
#define pi acos(-1)
double r[10005];
int main()
{
    int n,f,i,s,t,m;
    double sum2,sum1,v,left,right,mid;
    cin>>t;
    while(t--)
    {
        cin>>n>>f;
        sum1=0;
        for(i=0;i<n;i++)
        {
            cin>>m;
            r[i]=(double)m*m*pi;
            sum1+=r[i];
        }
        /*if(n==1)
        {
            sum2=(double)r[0]/(f+1);
            cout<<setiosflags(ios::fixed)<<setprecision(4)<<sum2<<endl;
            continue;
        }*/
        v=1.0*sum1/(f+1);
        left=0;
        right=v;
        while(right-left>0.000001)
        {
            mid=(left+right)/2.0;
            s=0;
            for(i=0;i<n;i++)
            {
                s+=(int)(r[i]/mid);//这里的int强制转换符,要把后面全括起来。。。
            }
            if(s>=f+1)
                left=mid;
            else
                right=mid;
            //cout<<left<<" "<<right<<" "<<mid<<" "<<s<<endl;
        }
        //cout<<maxn<<" "<<right<<endl;
        cout<<setiosflags(ios::fixed)<<setprecision(4)<<mid<<endl;
    }
    return 0;
}

2、Can you find it?-2141

思路:

这个题目就是很正常的二分,条件为left+1< right,但是这个题目又有点不同,它有三个序列,我之前是把第一二个排序然后暴力,第三个二分,结果爆时间了,后来发现题解是把第一第二个序列加起来排序,然后对这个新序列二分查找x-c[i]

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int t=0;
long long a[505],b[505],c[505];
long long sum[250005];
int main()
{
    int l,m,n,i,j,left,mid,right,flag,s,k;
    long long x,now;
    while(cin>>l>>n>>m)
    {
        k=0;
        for(i=0;i<l;i++)
            cin>>a[i];
        for(i=0;i<n;i++)
            cin>>b[i];
        for(i=0;i<m;i++)
            cin>>c[i];
        for(i=0;i<l;i++)
            for(j=0;j<m;j++)
                sum[k++]=a[i]+b[j];
        sort(sum,sum+k);//由a[i]+b[j]组成新序列
        cout<<"Case "<<++t<<":"<<endl;
        cin>>s;
        while(s--)
        {
            cin>>x;
            flag=0;
            for(i=0;i<m;i++)
            {
                left=0;
                right=k-1;
                now=x-c[i];
                while(left+1<right&&!flag)//二分查找
                {
                    mid=(left+right)/2;
                    if(now>=sum[mid])
                        left=mid;
                    else
                        right=mid;
                    //cout<<i<<" "<<j<<" "<<mid<<endl;
                }
                if(sum[left]==now||sum[right]==now)
                    flag=1;
                //cout<<i<<" "<<j<<" "<<left<<endl;
                if(flag)
                    break;
            }
            if(flag)
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }
    return 0;
}

3、Cup-hdu2289

思路:

这个题目跟第一题一样对精度要求很高,直接二分查找高度,条件是right-left>1e-7利用圆台体积公式v=mid*pi*(r*r+r*l+l*l)/3.0,像这种精度要求很高的就直接查找所求,不要转弯什么的,我朋友求的是半径,结果一下午都WA了

代码:

#include<cstdio>
#include<cstring>
#include<iomanip>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define pi acos(-1)
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        double r,R,H,V;
        cin>>r>>R>>H>>V;
        double left,right,mid,l,v;
        left=0;
        right=H;
        while(right-left>1e-7)
        {
            mid=(right+left)/2.0;
            l=mid*(R-r)/H+r;
            v=mid*pi*(r*r+r*l+l*l)/3.0;
            if(v<=V)
                left=mid;
            else
                right=mid;
            /*cout<<setiosflags(ios::fixed)<<setprecision(6);
            cout<<left<<" "<<right<<" "<<mid<<endl;*/
        }
        cout<<setiosflags(ios::fixed)<<setprecision(6)<<mid<<endl;
    }
    return 0;
}

4、Can you solve this equation?-hdu2199

思路:

这个题目我觉得好玄啊,我还是像之前那样用right-left>1e-6,结果不知道为什么他保留四位小数没有四省五入,输出6位是1.615150,保留4位就变成了1.6151,然后我就想着把他乘以100000然后手动判断要不要进位,结果乘以100000后就变成161514了。。。后面同学就帮我把条件改成fabs(a(mid)-y)>1.0e-6,输出6位还是1.615150,4位就变成1.6152了,这我就有点不懂了。。。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include <cmath>
using namespace std;
double a(double x)
{
    return 8*x*x*x*x + 7*x*x*x + 2*x*x + 3*x + 6;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        double y;
        scanf("%lf",&y);
        if(y<a(0)||y>a(100))
        {
            printf("No solution!\n");
            continue;
        }
        double l,r,mid;
        l=0;
        r=100;
        mid=(r+l)/2;
        while(fabs(a(mid)-y)>1.0e-6)
        {
            mid=(r+l)/2.0;
            if(a(mid)>y)
                r=mid;
            else
                l=mid;
            //cout<<l<<" "<<mid<<" "<<l<<endl;
        }
        //printf("%.10lf\n",mid);
        printf("%.4lf\n",mid);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值