《算法竞赛进阶指南》0x14 Hash POJ3349 雪花
题目链接:http://poj.org/problem?id=3349
给出n个雪花,每个雪花有六角,如果两个角序列从某位置开始正序或者逆序是相等的,那就称这两个雪花相等,问是否存在两个相等的雪花。
使用Hash的思想,构造一个哈希函数进行定址,如果hash值相等就从这个值的链表中取出每个数进行判断是否重合,处理冲突的方式是链地址法,一般可以用vector进行模拟。
代码如下:
#include<iostream> #include<cstdio> #include<string.h> using namespace std; #define maxn 100010 #define P 99991 typedef long long ll; int snow[maxn][6],a[6]; int head[maxn],nxt[maxn]; int tot=0; int n; int H(int* a){//构造哈希函数 int sum=0; int mul=1; for(int i=0;i<6;i++){ sum=(sum+a[i])%P; mul=(1ll*mul*a[i])%P;//模运算对乘法和加法可分配 } return (sum+mul)%P; } bool comp(int* a,int* b){//判断两个数组是否正序和逆序状态能相等 for(int i=0;i<6;i++){ for(int j=0;j<6;j++){ bool flag=true; for(int k=0;k<6;k++){//正向判断 if(a[(i+k)%6]!=b[(j+k)%6]) { flag=false; break; } } if(flag)return true; flag=true; for(int k=0;k<6;k++){//反向判断 if(a[(i+k)%6]!=b[(j-k+6)%6]) { flag=false; break; } } if(flag)return true; } } return false; } bool insert(int* a){ int val=H(a); for(int i=head[val];i;i=nxt[i]){ if(comp(a,snow[i]))return true; } ++tot; memcpy(snow[tot],a,6*sizeof(int)); nxt[tot]=head[val]; head[val]=tot; return 0; } int main(){ cin>>n; for(int i=1;i<=n;i++){ for(int j=0;j<6;j++)scanf("%d",&a[j]); if(insert(a)){ puts("Twin snowflakes found."); return 0; } } puts("No two snowflakes are alike."); return 0; }
每一个不曾起舞的日子,都是对生命的辜负。