题目大意:
有一个等式,
a*x1^2+b*x2^2+c*x3^2+d*x4^2=0,
a、b、c、d是[-50,50]之间的非零整数,
有一组解析(x1,x2,x3,x4),其中xi是[-100,100]之间的非零整数,
求有多少组解满足上式;
输入:多组测试用例,每组测试用例包含4个数:a,b,c,d,他们之间用一个或多个空格隔开,EOF结尾;
输出:每组测试用例解的个数;
==========基本思路=========
4个循环嵌套,回溯;但是这样的复杂度是n^4,在本题中就是10000 0000数量级的~
==========改进思路=========
把两项移到右边,就变成了左边两项与右边两项相等的式子;
这样只要分别计算左右两边相等的可能性即可,这样的复杂度就是10000数量级了~
==========================
a*x1^2 最大是50*10000 = 500000,其他三项也是,同理,最小是-500000;
两项的最大就是1000000,最小就是-1000000,这样就需要一个2000000的hash表来存储了;
但是要注意的是,最后hash表中存储的解得个数并不是最后结果,因为a、b、c、d四项可以互换位置,所以最后要乘以2^4 = 16才是解的个数;
Problem : 1496 ( Equations ) Judge Status : Accepted
RunId : 7413352 Language : C Author : qq1203456195
Code Render Status : Rendered By HDOJ C Code Render Version 0.01 Beta
#include <stdio.h> #include <string.h> int arr[101]; int hash[2000003]; int main() { int a,b,c,d; int i,j,sum; for (i=1;i<101;i++) arr[i] = i*i; while (scanf("%d%d%d%d",&a,&b,&c,&d)!=EOF) { if ((a>0 && b>0 && c>0 && d>0) || (a<0 && b<0 && c<0 && d<0)) { printf("0\n"); continue; } memset(hash,0,sizeof(hash)); for (i=1;i<=100;i++) { for (j=1;j<=100;j++) { hash[a*arr[i] + b*arr[j] + 1000000]++; } } sum = 0; for (i=1;i<=100;i++) { for (j=1;j<=100;j++) { sum += hash[-(c*arr[i] + d*arr[j]) + 1000000]; } } printf("%d\n",sum<<4); } return 0; }
=======再次改进=======
很明显,双重循环最多产生10000个数,所以开2000000个空间的数组明显是浪费了,怎样优化呢?1、数组,2、hash函数,3、冲突处理
开小数组是必须的,但是并不是越小越好,因为还要考虑冲突的现象,但是具体取多少的?HDUACM的课件中开的是50021,这是一个较大的素数,这样key的位置就可以通过比较常用的除模取余方法来确定了。其实hash函数以及处理冲突的方法有很多,没有固定的方法。
下边是HDUACM课件中使用的方法:
int hash(int k) { int t=k%MAX; if(t<0) t+=MAX; while(f[t]!=0&&g[t]!=k) t=(t+1)%MAX; return t; }
hash函数:t = k%MAX
处理冲突的方法:t = (t+1)%MAX
完整代码:f数组用来统计个数,g数组用来记录值;
// by laili #include<stdio.h> #include<memory.h> #define MAX 50021 int f[MAX],g[MAX]; int hash(int k) { int t=k%MAX; if(t<0) t+=MAX; while(f[t]!=0&&g[t]!=k) t=(t+1)%MAX; return t; } int main() { int a,b,c,d,p,i,j,s,n,t[101]; for(i=1;i<=100;i++) t[i]=i*i; while(scanf("%d%d%d%d",&a,&b,&c,&d)>0) { …… } }
while中代码:
if(a>0&&b>0&&c>0&&d>0||a<0&&b<0&&c<0&&d<0) { printf("0\n"); continue; } memset(f,0,sizeof(f)); n=0; for(i=1;i<=100;i++) for(j=1;j<=100;j++) { s=a*t[i]+b*t[j]; p=hash(s); g[p]=s; f[p]++; } for(i=1;i<=100;i++) for(j=1;j<=100;j++) { s=-(c*t[i]+d*t[j]); p=hash(s); n+=f[p]; } printf("%d\n",n*16);