《算法竞赛进阶指南》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;
}

 

posted @ 2020-06-17 15:08  WA自动机~  阅读(164)  评论(0编辑  收藏  举报