现在的位置: 首页 > 算法 > 正文

poj 2785 4 Values whose Sum is 0 (二分+枚举)

2018年09月23日 算法 ⁄ 共 1654字 ⁄ 字号 评论关闭

题目链接:http://poj.org/problem?id=2785

题目大意:  给出四个长度为n的列表(从上到下)

                    从每个列表分别取出一个数据,使得相加的结果为0

                    问最多存在多少种情况?

解题思路:  n的范围(1<=n<=4000),如果直接搜索 O(n^4) 那么肯定TLE.(计算机每秒钟的运行速度大概是10^8)

                    可以转化为O(2*n^2):

                    把1组和2组列表分别相加存到a[ ]数组中,3组和4组列表分别相加存到b[ ]数组中

                    只需要使得两个数组中元素a[i]=-b[j],那么这样的组合相加的结果就为0!

                    如果用朴素搜索会超时,所以存到数组之后,先排序,然后用二分法查找;

                    有一组数据很容易错,可以参考一下:

          PS:qsort居然会TLE,换成了sort就AC了,离线测试发现这道题用sort比qsort的效率高一倍!真奇怪

                    这道题还可以用Hash函数(散列函数),稍后再写吧!

易错数据:

                    4

                    0  0  0  0

                    0  0  0  0

                    0  0  0  0

                    0  0  0  0

                    256

代码:

#include <stdio.h>
#include <stdlib.h>
#include<algorithm>
using namespace std;
#define MAX_2 4001
#define MAX 16100000
int num[MAX_2][4],left[MAX],right[MAX];
int ErFen(int a[],int n,int x)  //二分查找,在数组right[]中查找x的位置,并且反馈x出现的次数
{
    int pd=0,ant,lefts,rights,middle;
    lefts=0;
    rights=n-1;
    while(lefts<=rights)
    {
        middle=(lefts+rights)>>1;
        if(a[middle]==x)
        {
            pd=1;
            break;
        }
        else if(x>a[middle])  lefts=middle+1;
        else   rights=middle-1;
    }
    if(pd)
    {
        for(ant=0;lefts<n;lefts++)  //***这里是易错点,函数需要返回的是x出现的次数!
        {
            if(a[lefts]==x)  ant++;
            else if(ant!=0&&a[lefts]!=x)  break;
        }
        return ant;
    }
    return -1;
}
 
int main()
{
    int n,m,i,j,k,temp;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0;i<n;i++)
        {
            for(j=0;j<4;j++)
            {
                scanf("%d",&num[i][j]);
            }
        }
        for(i=0,k=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                left[k]=num[i][0]+num[j][1];   //1,2组列表相加
                right[k++]=num[i][2]+num[j][3];  //3,4组列表相加
            }
        }
        sort(left,left+k);  //qsort排序会TLE
        sort(right,right+k);
        for(i=0,m=0;i<k;i++)
        {
            temp=ErFen(right,k,-left[i]);  //*** right[j]=-left[i]则满足相加为0
            if(temp!=-1)
                m+=temp;;
        }
        printf("%d\n",m);
    }
    return 0;
}

注:原创文章,转载请注明出处

抱歉!评论已关闭.