EOJ 1046 4个数的和为0
poj 2785 http://poj.org/problem?id=2785
eoj 1046 http://acm.cs.ecnu.edu.cn/problem.php?problemid=1046
思路: 散列(hash) + 拉链法去冲突;
具体过程:
把num[][1-4]按列划分为num[][1-2] 和 num[][3-4];
对 MAXN + num[i][1] + num[j][2] 散列;O(n^2 * len)
对 MAXN - num[i][3] - num[j][4] 查找;O(n^2 * len)
须使得被散列值为正,故用一大数 MAXN 保护;len为链表平均长度;
注意:
1.散列时,sum的地址由 hash(sum) = sum % MOD; 给出
2.MOD取一个大素数的动机是:使得平均查找效率更优;
也即散列得更均匀;
3.解决冲突的链表,这里用数组模拟,貌似比malloc快。
困惑:
按题意,节点总数最多为 4000*4000,
而我这里只开了NE个节点,觉得不够, 开大了又MLE。。。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #define MAXN (1<<29) 4 #define N 4005 5 #define MOD 3999971 6 #define NE 3999999 7 typedef struct 8 { 9 int n; 10 int cnt; 11 int next; 12 }E; 13 int ie; 14 E edge[NE]; //待分配的节点 15 16 int num[N][5]; 17 int hash[MOD+5]; 18 19 20 void init() 21 { 22 for(int i=0; i<=MOD; i++) 23 hash[i] = 0; 24 ie = 1; 25 } 26 int search(int n) 27 { 28 int a = n%MOD; 29 int p = hash[a]; 30 while(p) 31 { 32 if(edge[p].n == n) 33 return p; 34 p = edge[p].next; 35 } 36 return 0; //未找到 37 } 38 39 void add(int n) 40 { 41 int a = n%MOD; 42 int p; 43 if(p = search(n)) //找到,则仅将次数++ 44 edge[p].cnt ++; 45 46 else //未找到,则申请新节点,并插在头部。 47 { 48 edge[ie].n = n; 49 edge[ie].cnt = 1; 50 51 edge[ie].next = hash[a]; 52 hash[a] = ie++; 53 } 54 55 } 56 57 int main() 58 { 59 int n; 60 while(scanf("%d", &n) != EOF) 61 { 62 int i, j, cnt = 0; 63 for(i=1; i<=n; i++) 64 for(j=1; j<=4; j++) 65 scanf("%d", &num[i][j]); 66 67 init(); 68 69 for(i=1; i<=n; i++) 70 for(j=1; j<=n; j++) 71 add(MAXN + num[i][1] + num[j][2]); 72 73 for(i=1; i<=n; i++) 74 for(j=1; j<=n; j++) 75 { 76 int p = search(MAXN - num[i][3] - num[j][4]); 77 if(p) 78 cnt += edge[p].cnt; 79 } 80 81 printf("%d\n", cnt); 82 } 83 84 }