考察hash表:
每一个雪花都有各自的6个arm值,如果两个雪花从相同或者不同位置开始顺时针数或者逆时针数可以匹配上,那么这两个雪花就是相等的。
我们采用hash的方法,这样每次查询用时为O(1),总用时为O(n)。
hash的本质是把值映射到地址或者下标,如果不同的key值对应到相同的indice上的话,就需要进行chaining处理,吧indice指向一个链表,链表的每一个节点存储共享同一indice的不同key值。
因此问题的核心变成:吧相等的雪花映射到相同的indice上。这里雪花是一个特殊类型,我们不能直接映射,所以我们把每一片雪花的6个arm值的和取模作为该雪花的key值。
即:key=(arm[0]+arm[1]+arm[2]+arm[3]+arm[4]+arm[5]);
AND indice=key%prime
因为题目开出的雪花个数范围最大是10^6。所以我们取一个离10^6很近的99983作为prime(PS:事实上,在10^6周围的大质数都可以,可以随便挑一个)。
但这里又有一个问题:即使key值相同也不能代表两个雪花相同,所以我们当我们把所有的雪花映射到hash表上时,每一个indice指向的邻接表里存储的雪花仅仅是arm和相同。
-----------------------------------------------------------------------------------------
好了,现在我们开始查找相同雪花了:
顺序地,每一个雪花进行枚举,计算他的indice值,然后查看indice指向的邻接表是否为空,若为空,则说明还没有“相同”的雪花的记录。若不为空,则说明有arm和与当前雪花arm和相同的雪花在hash表中,所以我们进一步在indice指向的邻接表中逐一查找。如果发现有arm顺序“匹配”的雪花,就输出“Twin snowflakes found.”,然后程序结束。如果邻接表中没有我们想要的“相等”的雪花,那么我们就枚举下一个雪花。
如果枚举玩所有雪花都没有找到与之相等的雪花,则输出“No two snowflakes are alike.”,程序结束。
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<map> #include<vector> using namespace std; const int max_size=100010; const int prime=99991; vector<int> hsh[prime]; int arm[max_size][6]; int n; bool isTheSame(int a,int b){ for(int i=0;i<6;i++){ if((//clockwise 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]) || //counter clockwise ( 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]*2; } key=sum%prime; vector<int>::size_type k; for(k=0;k<hsh[key].size();k++){ if(isTheSame(i,hsh[key][k])){ printf("Twin snowflakes found.\n"); exit(0); } } hsh[key].push_back(i); } printf("No two snowflakes are alike.\n"); }