题目链接: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;
}
注:原创文章,转载请注明出处