【POJ3349 Snowflake Snow Snowflakes】【Hash表】
最近在对照省选知识点自己的技能树 今天是Hash
题面
大概是给定有n个6元序列
定义两个序列相等 当两个序列各自从某一个元素开始顺时针或者逆时针旋转排列能得到两个相同的序列
求这n个6元序列中是否有相等的序列
解释相等序列的样例
顺时针:如 1 2 3 4 5 6 与 2 3 4 5 6 1 相等
逆时针:如 1 2 3 4 5 6 与 6 5 4 3 2 1 相等
算法
对于各种类型的数列 字符串是否相等问题我们都可以用Hash解决
我们对一个序列A 定义其哈希值为 \(H(A) = (\sum^{6}_{j = 1}A_{i,j} + \prod^{6}_{j = 1}A_{i,j}) mod P\)
P的取值稍后讨论
我们知道对于组成数字一样的两个序列A和B 显然有\(H(A) = H(B)\)
我们用领接表来存储这些哈希值相等的序列在总序列中的下标,然后我们把当前序列A与在哈希表中哈希值同A一样的序列进行比较即可
如果没有匹配的 我们则把A的首个元素下标 存入哈希表
P的取值
在哈希表中 我们通常取P与数据范围N接近的质数 这样可以让哈希表尽量的均匀 可以提高查找效率 这里最大的数据范围是 600000 我们取\(P = 517619\)
代码
#include <iostream>
#include <cstdio>
#define ll long long
#define M 600010
#define MOD 517619
using namespace std;
ll num[M], n, head[M];
struct P {
ll biao, next;
} lian[M];
bool cheek(ll n1, ll n2) {
bool p;
for (ll i = 1; i <= 6; i++) //顺
{
p = 1;
for (ll j = 1; j <= 6; j++) {
ll now = n1 + (i + j - 1) % 6;
if (num[now] != num[n2 + j - 1]) {
p = 0;
break;
}
}
if (p)
return 1;
}
for (ll i = 1; i <= 6; i++) //逆
{
p = 1;
for (ll j = 1; j <= 6; j++) {
ll now = n1 + (i + j - 1) % 6;
if (num[now] != num[n2 + 6 - j]) {
p = 0;
break;
}
}
if (p)
return 1;
}
return 0;
}
bool insert(ll num, ll front) {
ll now = head[num];
if (now == 0) {
lian[++lian[0].biao].biao = front;
lian[lian[0].biao].next = head[num];
head[num] = lian[0].biao;
return 0;
} else
for (; now; now = lian[now].next) {
if (cheek(lian[now].biao, front))
return 1;
}
lian[++lian[0].biao].biao = front;
lian[lian[0].biao].next = head[num];
head[num] = lian[0].biao;
return 0;
}
int main() {
scanf("%lld", &n);
for (ll i = 1; i <= 6 * n; i += 6) {
ll sum = 0;
ll cheng = 1;
for (ll j = 1; j <= 6; j++) {
scanf("%lld", &num[i + j - 1]);
sum = (sum + num[i + j - 1]) % MOD;
cheng = (cheng * num[i + j - 1]) % MOD;
}
ll key = (sum + cheng) % MOD;
if (insert(key, i)) {
puts("Twin snowflakes found.");
return 0;
}
}
puts("No two snowflakes are alike.");
}
```(奇怪 代码块渲染出了点问题)