poj Snowflakes snow snowflakes 哈希

题意:给出n个雪花的六条边的长度,求出是否有两个相同的雪花,即边的大小和顺序相同。

因为只要考虑是否存在相同的雪花,结合雪花边长可能较大的条件,考虑哈希。

需要顺时针和逆时针枚举比较。


PS:用了读入优化,然而还是3500ms飘过。。。

先贴上这份代码,优化在后面。

#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

typedef long long ll;

const int mod = 1e6 + 7;
const int maxn = 1e5 + 1;

int n;
int hash[mod];
int flag = 0;

struct node {
        int tag;
        int a[6];
} snow[maxn];

inline int Hash(node u) {
        int t = 0;
        for (int i = 0; i < 6; i++) t += u.a[i];
        return t % mod;
}

inline bool clockwise(node u, node v) {
        bool sig;
        for (int i = 0; i < 6; i++) {
                sig = 0;
                int p = i;
                for (int j = 0; j < 6; j++) {
                        if (u.a[p] != v.a[j]) {
                                sig = 1;
                                break;
                        }
                        p = (p + 1) % 6;
                }
                if (!sig) break;
        }
        if (!sig) return true;
        return false;
}

inline bool counterClockwise(node u, node v) {
        bool sig;
        for (int i = 0; i < 6; i++) {
                sig = 0;
                int p = i;
                for (int j = 0; j < 6; j++) {
                        if (u.a[p] != v.a[j]) {
                                sig = 1;
                                break;
                        }
                        p = (p + 5) % 6;
                }
                if (!sig) break;
        }
        if (!sig) return true;
        return false;
}

inline void hashit(node u) {
        int t = Hash(u);
        while (hash[t] != -1) {
                if (clockwise(u, snow[hash[t]]) || counterClockwise(u, snow[hash[t]])) {
                        flag = 1;
                        return;
                }
                t = (t + 10) % mod;
        }
        hash[t] = u.tag;
}

void read() {
        char c;
        n = 0;
        while (~scanf("%c", &c) && c != '\n') n = 10 * n + c - '0';
        int t, cnt;
        for (int i = 0; i < n; i++) {
                snow[i].tag = i;
                t = cnt = 0;
                while (c = getchar()) {
                        if (c == ' ') {
                                snow[i].a[cnt++] = t;
                                t = 0;
                                continue;
                        }
                        else if (c == '\n') {
                                snow[i].a[cnt++] = t;
                                break;
                        }
                        t = 10 * t + c - '0';
                }
                // for (int j = 0; j < cnt; j++) printf("%d%c", snow[i].a[j], " \n"[j == cnt - 1]);
        }
}

int main() {
        memset(hash, -1, sizeof(hash));
        read();
        for (int i = 0; i < n; i++) if (!flag) {
                hashit(snow[i]);
        }
        if (flag) puts("Twin snowflakes found.");
        else puts("No two snowflakes are alike.");
        return 0;
}

看了看discuss,archerstarlee总结了大家用的Hash方法,上面的是直接相加模大质数。

然后我试了最后一种,时间降到2700ms。

const int mod = 1e6 + 3;

inline int Hash(int u) {
        return ((a[u][0] + a[u][2] + a[u][4]) ^ (a[u][1] + a[u][3] + a[u][5])) % mod;
}

当我用了数的平方和取模时,简直吓死。。


inline int Hash(int u) {
        ll t = 0;
        for (int i = 0; i < 6; i++)
                t += (ll)a[u][i] * a[u][i] % mod; // mod = 1e6 + 3;
        return (int)t % mod;
}
“六个数中非零数的积再乘上一个大质数,然后模一个100w上下的数。
自己拿随机数据测下来110w左右的效果最好,随机情况下数据量是10w的时候hash值相同的情况只有6k多个,几乎可以忽略。(by  killertom)”

这个评测结果也很好,579ms。

总而言之,哈希函数的选取很重要,慢慢攒经验吧。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值