HDU-2141(二分查找+最详细+没有之一)

HDU-2141(二分查找+最详细+没有之一)

AC:当你点进来这篇文章,请一定要认真看完,这篇文章花了一个小时完成,所以要有点耐心看完哦,这个题不是特别难,我把关键代码很详细解释了,坚持看完,一定能看懂!
Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.
Input
There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.
Output
For each case, firstly you have to print the case number as the form “Case d:”, then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print “YES”, otherwise print “NO”.
Sample Input
3 3 3
1 2 3
1 2 3
1 2 3
3
1
4
10
Sample Output
Case 1:
NO
YES
NO

个人分析:

先分析一下题意:第一行就是对应你后面输出的ABC的个数 第二行就是输入的A 第三行就是输入的B 第四行就是输入的C 后面就是输入的X 题目的输出就是看是否存在A+B+C=X 一开始的想法就是把A+B+C合成一个新的数组 然后就是通过X二分查找 但是呢,这个时间复杂度得有多大啊,然后空间复杂度也很大呢,500X500X500 至少这么多 所以转换思路 把原问题转成A+B=X-C了,那么我们就将AB合在一起形成新的数组 然后用X-C来二分查找 我先说自己写的二分查找吧详细代码如下:(解释在代码下面)

int find(int l,int r,int x)
{
    int mid=(l+r)/2;
    if(ab[mid]==x)
    {
        return 1;
    }
    else
    {
        if(l==r)
        {
            return 0;
        }
        else if(x<ab[mid])
        {
            return find(l,mid,x);
        }
        else
        {
            return find(mid+1,r,x);
        }
    }
}

对于以上代码的解释:
传递三个参数,左右,查找的值,先计算中间值mid 然后做比较 因为原本的ab数组通过sort排序了的(默认从小到大) 二分思想:如果x比中间那个值小,那么肯定就在中间mid的前面 所以递归(左,中-1,查找的值x) 相反,那就在右边 递归(中+1,右,查找的值x) 但是这里我也有点疑惑对于小于中间那个值的时候 按照二分思想,我写mid-1会报时间超限 但是按上面代码写mid写就AC 了,如果你们清楚地,可以留言评论,看到我会感谢的! 后面发现c++里有内置的二分函数binart_search方法 我也把源码放在了最后面

下面是将原问题A+B+C=X 简化成A+B=X-C:(解释在代码下面)

	 int len=0;
        for(int i=0;i<L;i++)
        {
            for(int j=0;j<N;j++)
            {
                ab[len++]=a[i]+b[j];
            }
        }
        sort(ab,ab+len);
        int t;
        cin>>t;
        int ss=0;
        int flag=0;
        while(t--)
        {
            int x;
            cin>>x;
            if(ss==0)
            {
                ss=1;
                printf("Case %d:\n",++cnt);
            }
            flag=0;
            for(int k=0;k<M&&flag==0;k++)
            {
                flag=find(0,len-1,x-c[k]);
            }
            if(flag)
            {
                cout<<"YES"<<endl;
            }
            else
            {
                cout<<"NO"<<endl;
            }

        }

对以上代码的解释:
通过两个for循环,将AB整合到一个数组ab里面去了,但注意ab数组开的时候最少都要500X500大小 int ab[250008];这是我开的数组大小 一开始没想那么多,就直接定义了10008大小 后面报错了 所以开数组尽量大一点没问题的!

flag=0;
for(int k=0;k<M&&flag==0;k++)
 {
    flag=find(0,len-1,x-c[k]);
 }

然后就是这段代码,二分查找的入口 这里其实写的没有后面的源代码写的好~

个人感受:

刚看到这个题是完全没什么思路,就想着用数组暴力解,但是训练时候提示是用二分查找,对于刚接触的我来说,二分是啥?所以花了一个上午的时间来学习二分,算是熟悉了,后面又了解到原来c++里面也有写好了的二分查找函数,只需要用就可以了 binary_search 在头文件#include<-algorithm->里面(它是个关键词 显示不出来 所以这样写了 别见怪哦~)这个题挺好的,让我接触了二分法,也是对分治的入门!
具体代码如下:
AC

  • 自己写二分法find函数

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[508],b[508],c[508];
int ab[250008];
int cnt=0;
int find(int l,int r,int x)
{
    int mid=(l+r)/2;
    if(ab[mid]==x)
    {
        return 1;
    }
    else
    {
        if(l==r)
        {
            return 0;
        }
        else if(x<ab[mid])
        {
            return find(l,mid,x);
        }
        else
        {
            return find(mid+1,r,x);
        }
    }
}
int main()
{
    int L,N,M;
    while(cin>>L>>N>>M)
    {
        for(int i=0;i<L;i++)
        {
            cin>>a[i];
        }
        for(int i=0;i<N;i++)
        {
            cin>>b[i];
        }
        for(int i=0;i<M;i++)
        {
            cin>>c[i];
        }
        int len=0;
        for(int i=0;i<L;i++)
        {
            for(int j=0;j<N;j++)
            {
                ab[len++]=a[i]+b[j];
            }
        }
        sort(ab,ab+len);
        int t;
        cin>>t;
        int ss=0;
        int flag=0;
        while(t--)
        {
            int x;
            cin>>x;
            if(ss==0)
            {
                ss=1;
                printf("Case %d:\n",++cnt);
            }
            flag=0;
            for(int k=0;k<M&&flag==0;k++)
            {
                flag=find(0,len-1,x-c[k]);
            }
            if(flag)
            {
                cout<<"YES"<<endl;
            }
            else
            {
                cout<<"NO"<<endl;
            }

        }
    }


    return 0;
}

  • 调用c++二分法函数(优化)

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int a[508],b[508],c[508];
int ab[250008];
int cnt=0;
int main()
{
    int L,N,M;
    while(cin>>L>>N>>M)
    {
        for(int i=0;i<L;i++)
        {
            cin>>a[i];
        }
        for(int i=0;i<N;i++)
        {
            cin>>b[i];
        }
        for(int i=0;i<M;i++)
        {
            cin>>c[i];
        }
        int len=0;
        for(int i=0;i<L;i++)
        {
            for(int j=0;j<N;j++)
            {
                ab[len++]=a[i]+b[j];
            }
        }
        sort(ab,ab+len);
        int t;
        cin>>t;
        int ss=0;
        int flag=0;
        while(t--)
        {
            int x;
            cin>>x;
            if(ss==0)
            {
                ss=1;
                printf("Case %d:\n",++cnt);
            }
            for(int k=0;k<M;k++)
            {
                flag=binary_search(ab,ab+len,x-c[k]);
                if(flag)
                {
                    break;
                }
            }
            if(flag)
            {
                cout<<"YES"<<endl;
            }
            else
            {
                cout<<"NO"<<endl;
            }

        }
    }


    return 0;
}

学如逆水行舟,不进则退

猜你喜欢

转载自blog.csdn.net/weixin_42429718/article/details/87710087