简单哈希
当我们对若干复杂信息进行统计时,可以用Hash函数把这些复杂的信息映射到一个容易维护的值域内,因为值域变得简单和范围变小, 会造成两个不同的原始信息被Hash函数映射成同一个值,所以我们要处理这种情况。有一种叫“开散列”解决方案是建立一个邻接表结构,以Hash函数的值域作为表头数组head,映射后的值相同的原始信息被分到同一个表头的链表中的不同部位,链表的节点可以存一些原始信息和数据。
Hash主要有两个操作,一个是计算哈希后的值,第二个是定位到对应链表上依次遍历比较。
建立一个大小等于值域的数组进行统计和映射,其实就是简单的Hash思想。
哈希函数就是(xmodP)+1;P是一个比较大的质数,但不超过N,显然,这个Hash函数吧数列A分成P类,我们可以依次考虑数列中的每个数A[i],定位到head[A[i]]然后遍历并插入。
比如POJ3349 题目链接
我们可以通过哈希每个雪花的边之和来把雪花分成几个不同的类,然后在遍历插入的时候查询该类有没有和当前处理的雪花匹配的,即可快速的找出是否有一样的雪花
代码附上:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAX = 100010;
const int mod = 99991;
vector<int> hsh[mod];//如果mod不加 const 会报错不能识别hsh
int arm[MAX][6];
int n;
bool issame(int a, int b) {//逆时针or顺时针匹配 (我最开始是找一个数两边的值是否相等)
for(int i = 0; i < 6; i++) {
if((arm[a][0] == arm[b][i] && arm[a][1] == arm[b][(i+1)%6] &&
arm[a][2] == arm[b][(i+2)%6] && arm[a][3] == arm[b][(i+3)%6] &&
arm[a][4] == arm[b][(i+4)%6] && arm[a][5] == arm[b][(i+5)%6])
||
(arm[a][0] == arm[b][i] && arm[a][1] == arm[b][(i+5)%6] &&
arm[a][2] == arm[b][(i+4)%6] && arm[a][3] == arm[b][(i+3)%6] &&
arm[a][4] == arm[b][(i+2)%6] && arm[a][5] == arm[b][(i+1)%6]))
return true;
}
return false;
}
int main() {
scanf("%d", &n);
long long sum, key;
for(int i = 0; i < n; i++) {
for(int j = 0; j < 6; j++) {
scanf("%d", &arm[i][j]);
}
}
for(int i = 0; i < n; i++) {
sum = 0;
for(int j = 0; j < 6; j++) {
sum += arm[i][j];
}
key = sum % mod;
for(int k = 0; k < hsh[key].size(); k++) {//如果是空的,就进不去
if(issame(i, hsh[key][k])) {//不是空的,就去匹配顺序
printf("Twin snowflakes found.\n");
return 0;
}
}
hsh[key].push_back(i);//第i个放到该key里 (映射关系)
}
printf("No two snowflakes are alike.\n");
}