(最易理解)51Nod

来源:互联网 发布:淘宝特卖9.9 编辑:程序博客网 时间:2024/06/03 17:43

题目描述:
给出N个整数,你来判断一下是否能够选出4个数,他们的和为0,可以则输出”Yes”,否则输出”No”。
Input
第1行,1个数N,N为数组的长度(4 <= N <= 1000)
第2 - N + 1行:Aii(-10^9 <= Aii <= 10^9)
Output
如果可以选出4个数,使得他们的和为0,则输出”Yes”,否则输出”No”。
Sample Input
5
-1
1
-5
2
4
Sample Output
Yes

解题报告:

  • 折半枚举的思路
  • 要求a+b+c+d = 0 ,那么转化为 c+d = -a - b
  • 如果随机枚举,去除重复比较烦,不太好弄,那么可以先给原数组排序
  • 排序后可以使用定序的技巧,可以比较下面俩个代码,自己输出体会一下

代码一:

for(int i = 0;i < n;i++){    for(int j = 0;j < n;j++)    {        for(int k = 0;k < n;k++)        {            for(int l = 0;l < n;l++)            {                printf("%d  %d %d %d = %d\n",i,j,k,l,a[i] + a[j] + a[k] + a[l]);            }        }    }}

代码二:

for(int i = 0;i < n;i++){    for(int j = i+1;j < n;j++)    {        for(int k = j+1;k < n;k++)        {            for(int l = k+1;l < n;l++)            {                printf("%d  %d %d %d = %d\n",i,j,k,l,a[i] + a[j] + a[k] + a[l]);            }        }    }}
  • 四重循环会超时,折半枚举加双向搜索
  • 直接上代码:
    -
# include <cstdio># include <algorithm>using namespace std;const int maxn = 1005;int main(){    int n;    long long a[maxn];    scanf("%d",&n);    for(int i = 0;i < n;i++)    {        scanf("%lld",&a[i]);    }    sort(a,a+n);  //将原数组排序    for(int i = 0;i < n;i++) //枚举第一个数    {        for(int j = i+1;j < n;j++) //枚举第二个数        {            long long res = -a[i] - a[j]; //前俩个数的和的相反值等于后俩个数的和            int l = j+1,r = n-1;   //l枚举第三个数,r枚举第四个数            while(l<r)            if(res == (a[l] + a[r]))              {                printf("Yes\n");                return 0;            }            else if(res > (a[l] + a[r]))  //如果大于,说明后俩个数和较小,            {                             //那么l++,因为数组已经排序,l+1肯定大于l                l++;            }            else if(res < (a[l] + a[r]))  //同理小于的话,说明后俩个数和太大,就减小r的值            {                r--;            }        }    }    printf("No\n");    return 0;}
  • 上面的源码就是将内层的俩个循环改为双向搜索,改进时间复杂度。
  • 如果有什么地方不懂可以留言,我会回复答疑
原创粉丝点击