#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const int MAX_LENGTH = 100000;
struct snowFlakeInfo{
int armLength[6];
char used;
int hashValue;
};
typedef struct snowFlakeInfo snowFlakeInfo;
const int ARM_NUM = 6;
const int BIG_PRIME = 1000003;
snowFlakeInfo hashArray[1000010];
unsigned int hash(int * input) {
unsigned long long powSum = 0;
int i;
for (i = 0; i < ARM_NUM; i++) {
if (input[i]) {
powSum += input[i]*input[i];
}
}
return powSum % BIG_PRIME;
}
int comp(const void *a,const void *b)
{
return *(int*)a - *(int*)b;
}
char equal(int * sf1, int * sf2) {
int i;
qsort(sf1, ARM_NUM, sizeof(int), comp);
qsort(sf2, ARM_NUM, sizeof(int), comp);
for (i = 0; i < ARM_NUM; i++) {
if (sf1[i] != sf2[i]) {
return 0;
}
}
return 1;
}
const int sfSize = 24;
char fill(int * input) {
unsigned int hashValue = hash(input);
unsigned int insertPos = hashValue;
while(1) {
if (!hashArray[insertPos].used) {
// memcpy(&(hashArray[insertPos].armLength), input, sfSize);
int i = 0;
for (; i< ARM_NUM; i++) {
hashArray[insertPos].armLength[i] = input[i];
}
hashArray[insertPos].used = 1;
hashArray[insertPos].hashValue = hashValue;
return 0;
} else {
if (hashArray[insertPos].hashValue == hashValue) {
if (equal(input, hashArray[insertPos].armLength)) {
return 1;
}
}
insertPos++;
if (insertPos >= BIG_PRIME+1) {
insertPos = 0;
}
}
}
}
char check(int * input) {
return fill(input);
}
int main() {
int num;
// while(scanf("%d", &num) > 0) {
int i = 0;
char hasSame = 0;
scanf("%d", &num);
memset(hashArray, 0, sizeof(hashArray));
for (; i < num; i++) {
int tmp[6] = {0};
int j = 0;
for (; j <= 5; j++) {
scanf("%d", tmp+j);
}
if (!hasSame && check(tmp)) {
// printf("%d\n", hash(tmp));
hasSame = 1;
}
}
if (hasSame) {
printf("Twin snowflakes found.\n");
} else {
printf("No two snowflakes are alike.");
}
// }
#include <stdlib.h>
#include <string.h>
const int MAX_LENGTH = 100000;
struct snowFlakeInfo{
int armLength[6];
char used;
int hashValue;
};
typedef struct snowFlakeInfo snowFlakeInfo;
const int ARM_NUM = 6;
const int BIG_PRIME = 1000003;
snowFlakeInfo hashArray[1000010];
unsigned int hash(int * input) {
unsigned long long powSum = 0;
int i;
for (i = 0; i < ARM_NUM; i++) {
if (input[i]) {
powSum += input[i]*input[i];
}
}
return powSum % BIG_PRIME;
}
int comp(const void *a,const void *b)
{
return *(int*)a - *(int*)b;
}
char equal(int * sf1, int * sf2) {
int i;
qsort(sf1, ARM_NUM, sizeof(int), comp);
qsort(sf2, ARM_NUM, sizeof(int), comp);
for (i = 0; i < ARM_NUM; i++) {
if (sf1[i] != sf2[i]) {
return 0;
}
}
return 1;
}
const int sfSize = 24;
char fill(int * input) {
unsigned int hashValue = hash(input);
unsigned int insertPos = hashValue;
while(1) {
if (!hashArray[insertPos].used) {
// memcpy(&(hashArray[insertPos].armLength), input, sfSize);
int i = 0;
for (; i< ARM_NUM; i++) {
hashArray[insertPos].armLength[i] = input[i];
}
hashArray[insertPos].used = 1;
hashArray[insertPos].hashValue = hashValue;
return 0;
} else {
if (hashArray[insertPos].hashValue == hashValue) {
if (equal(input, hashArray[insertPos].armLength)) {
return 1;
}
}
insertPos++;
if (insertPos >= BIG_PRIME+1) {
insertPos = 0;
}
}
}
}
char check(int * input) {
return fill(input);
}
int main() {
int num;
// while(scanf("%d", &num) > 0) {
int i = 0;
char hasSame = 0;
scanf("%d", &num);
memset(hashArray, 0, sizeof(hashArray));
for (; i < num; i++) {
int tmp[6] = {0};
int j = 0;
for (; j <= 5; j++) {
scanf("%d", tmp+j);
}
if (!hasSame && check(tmp)) {
// printf("%d\n", hash(tmp));
hasSame = 1;
}
}
if (hasSame) {
printf("Twin snowflakes found.\n");
} else {
printf("No two snowflakes are alike.");
}
// }
}
C 31484K 2438MS
第一次干hash, 以前都是用用STL的hashMap, 这次自己亲自撸了一把, 感受不一样呀。
真是多谢discuss有好心人列举了hash的办法:
1. 直接相加, 把(总和%大质数)为key. 2. 平方和相加, 把(总和%大质数)为key. 3. 从小到大的顺序, 对v[i]<<(i*3)依次异或, 然后模一个大质数作为key.(by hust07p43) 4. 六个数中非零数的积再乘上一个大质数,然后模一个100w上下的数。 自己拿随机数据测下来110w左右的效果最好,随机情况下数据量是10w的时候hash值相同的情况只有6k多个,几乎可以忽略。(by killertom) 5. 依次对每个数异或所得的数作为key. (by archerstarlee) 6. (a[0] + a[2] + a[4])&(a[1] + a[3] + a[5]), 再模一个大质数. 中间的&还可以改成'|' 或者'^'.非常巧妙! 我采用'^'得到最快的719ms. (只对本题适用的hash方法) 其实最关键的就是要开放式寻址解决hash冲突, 不要以为hash就能解决问题了. 最后就是用getchar和gets来进行输入转换更为快速. G++比GCC快一些. 欢迎大家补充自己更为快速的Hash方法.我这里用的是第2个hash法, 注意的是平方和最好搞成long(我直接搞了long long), 不然RE, 唉一个小问题,耽误了很长时间.
大质数我用的是1000003, 后面几种办法有时间也尝试下.
对于hash冲突的处理, 因为自己记的最熟的是拉链法, 反而想尝试一把开放式寻址法,这种方法不用动态申请空间,遍历的时候, 在某些情况下效率也高点.
步骤描述出来也简单,就是求出此snowflake的hash值以后, 在之前开的hash数组里找对应位置是不是已经填进东西了,
如果填进了,那么就比较此处存储的hash值是否和当前的一样,如果一样,那么就真正比较arms的值(这题的arm值挺奇葩的,我是先排了序,再顺序比的, 找不出更好的)。如果hash不等或者arm不等, 那么就继续向后面找,到尾了就再从0开始,直到找到一个没填的位置(一定可以找到, 按照这种搞法), 如果找到了完全一样的, 就可以认为same snowflake了, 还要注意的是,一般为了效率, 都是边输入就边开始存hash做判定的,在有了same snowflake以后, 就不用再hash 和 比较了, 但是还是要继续接收输入. 搞一个标志位,在最后输入全部处理完以后再根据其值输出结果就可以了.