原题链接:https://www.acwing.com/problem/content/description/139/
题意:问能否在给出的雪花里找出两片相同的雪花,顺时针或逆时针相同都行。
思路:每片雪花有6个角,且每个角都有长度。那么我们可以利用设置一个hash函数来存储每片雪花的值,用snow[maxn][6]储存每片雪花的每个角的值。我们使用邻接表存储,当输入一片新的雪花时,先求出它的hash值,找到对应的表头,然后再扫描其对应的链表,挨个比对每一个角是否相同。
邻接表模板:
//加入有向边(x,y),权值为z
void add(int x, int y,int z){
++tot;
ver[tot]=y;
edge[tot]=z;
nexxt[tot]=head[x];
head[x]=tot;//在表头x处插入
}
//访问从x出发的所有边
for(int i=head[x];i;i=nexxt[i]){
int y=ver[i],z=edge[i];
//找到了一条有向边(x,y),权值为z
}
hash函数相关介绍:https://blog.csdn.net/u012835097/article/details/79407591
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
int n,tot,p=92083,snow[maxn][6],head[maxn],ne[maxn],a[6];;
int H(int *a){//获得hash函数值,此处定义为 (sum+mul)%p,p为小于范围的很大质数
int sum=0;
ll mul=1;
for(int i=0;i<6;i++){
sum=(sum+a[i])%p;
mul=mul*a[i]%p;
}
return (sum+mul)%p;
}
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]) flag=0;//逆时针
}
if(flag) return 1;
}
return 0;
}
bool insert(int *a){
int val=H(a);//数组a对应的hash值
//遍历表头head[val]指向的链表,寻找形状相同的雪花
for(int i=head[val];i;i=ne[i]){
if(equal(snow[i],a)) return 1;
}
//没有找到,执行插入操作
++tot;
for(int i=0;i<6;i++){
snow[tot][i]=a[i];//赋值更新
}
//在表头处插入 ,邻接表
ne[tot]=head[val];
head[val]=tot;
return 0;
}
int main(){
cin>>n;
while(n--){
for(int j=0;j<6;j++){
cin>>a[j];
}
if(insert(a)){//每输入一组,就比对一下
puts("Twin snowflakes found.");
return 0;
}
}
puts("No two snowflakes are alike.");
return 0;
}