思路:这里相同的雪花一定是六个角的长度之和,长度之积都相同,就想一般的数字hash中的余数一样,只有余数相同才能去找数字是否存在。这里用的拉链法来做。
哈希表暴力代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>
#include<map>
using namespace std;
const int N=1e5+10,mod=1e5+3;
int snow[N][6];
int h[N],e[N],ne[N],idx;//因为是以邻接表的形式存,不需要开数倍
int n;
int hh(int a[])//获取该雪花在哪条链表中
{
int sum=0,mul=1;
for(int i=0;i<6;i++)
{
sum=(sum+a[i])%mod;
mul=(long long)mul*a[i]%mod;
}
return (mul+sum)%mod;
}
bool equal(int a[],int b[])//判断两篇雪花是否相同
{
for(int i=0;i<6;i++)
for(int j=0;j<6;j++)
{
bool flag=1;
for(int k=0;k<6;k++)
if(a[(i+k)%6]!=b[(j+k)%6]) flag=0;
if(flag) return 1;
flag=1;
for(int k=0;k<6;k++)
if(a[(i+k)%6]!=b[(j-k+6)%6]) flag=0;
if(flag) return 1;
}
return 0;
}
bool insert(int a[])//询问或插入一片新雪花
{
int t=hh(a);
for(int i=h[t];i;i=ne[i])
{
if(equal(snow[i],a))return 1;
}
idx++;//这里会从1开始,所以h数组不用初始化为-1.
memcpy(snow[idx],a,6*sizeof(int));
ne[idx]=h[t];
h[t]=idx;
return 0;
}
int main()
{
cin>>n;
// memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
{
int a[8];
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;
}
最小表示法+哈希表代码:
思路:将每一个字符串正向反向各求一次最小表示,求出哈希值,用stl中的哈希表来存,当有两个相同的哈希值时说明有两片一模一样的雪花。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_set>
using namespace std;
typedef unsigned long long ull;
const int N=1e5+10,p=131;
int n;
int a[N][13];
int b[N][13];
int left1[N],right1[N];
unordered_set<ull>s;
int get_min(int s[])
{
int i=1,j=2,k;
while(i<=6&&j<=6)
{
for(k=0;k<6&&s[i+k]==s[j+k];k++);
if(k==6)break;
if(s[i+k]>s[j+k])
{
i=i+k+1;
if(i==j) i++;
}else
{
j=j+k+1;
if(i==j) j++;
}
}
return min(i,j);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=6;j++)
{
scanf("%d",&a[i][j]);
a[i][j+6]=a[i][j];
}
left1[i]=get_min(a[i]);
}
memcpy(b,a,sizeof a);
for(int i=1;i<=n;i++)
{
reverse(b[i]+1,b[i]+13);//存反向字符串的最小表示
right1[i]=get_min(b[i]);
}
bool flag=0;
for(int i=1;i<=n;i++)
{
ull sum1=0,sum2=0;
for(int j=0;j<6;j++)
{
sum1=sum1*p+a[i][left1[i]+j];
sum2=sum2*p+b[i][right1[i]+j];
}
if(s.count(sum1)!=0)
{
flag=true;
break;
}else s.insert(sum1);
if(sum1!=sum2)
{
if(s.count(sum2)!=0)
{
flag=true;
break;
}else s.insert(sum2);
}
}
if(flag)puts("Twin snowflakes found.");
else puts("No two snowflakes are alike.");
return 0;
}