poj-3349

#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.");
        }
        
    // }

}


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 和 比较了, 但是还是要继续接收输入. 搞一个标志位,在最后输入全部处理完以后再根据其值输出结果就可以了.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值