正题
洛谷评测记录:https://www.luogu.org/recordnew/lists?uid=52918&pid=SP4354
POJ题目链接:http://poj.org/problem?id=3349
题目大意
有n片雪花,他们6个角有不同的长度,如果两片雪花6个角长度相同(可以不同方向),那么就是两片相同的雪花,求第一个相同的雪花。
解题思路
我们可以用hash判断两片雪花是否相同,然后用每片雪花的最小表示法,这样就不需要别的判断。
code
#include<cstdio>
#include<algorithm>
#define ymm 160001
#define ull unsigned long long
int a[21],ans1,ans2,ans,n;
ull h[ymm];
using namespace std;
unsigned hash(ull x){
unsigned pos=x%ymm,i=0;
while (i<ymm&&h[(pos+i)%ymm]&&h[(pos+i)%ymm]!=x) i++;
return (pos+i)%ymm;
}//哈希表
void small()//最小表示法
{
int i=7,j=8,k;
while(i<=12&&j<=12){
for(k=0;k<=6&&a[i+k]==a[j+k];k++);
if(k==6) break;
if(a[i+k]>a[j+k]){
i+=k+1;
if(i==j) i++;
}
else{
j+=k+1;
if(i==j) j++;
}
}//正序
ans1=min(i,j);
i=12,j=11;
while(i>=7&&j>=7){
for(k=0;k<=6&&a[i-k]==a[j-k];k++);
if(k==6) break;
if(a[i-k]>a[j-k]){
i-=k+1;
if(i==j) i--;
}
else{
j-=k+1;
if(i==j) j--;
}
}//逆序
ans2=max(i,j);
}
bool insert()
{
small();
int ans=ans1,x;bool f=false;
ull sum=0;
int i;
for(i=0;i<6&&a[ans1+i]==a[ans2-i];i++);
if(a[ans1+i]>a[ans2-i]) ans=ans2,f=true;
//求顺时和逆时的最小
if(!f)
for(i=ans;i<ans+6;i++) sum=sum*13131+a[i];
else
for(i=ans;i>ans-6;i--) sum=sum*13131+a[i];
//计算hash值
if(h[(x=hash(sum))]==sum) return 1;
h[x]=sum;return 0;
//判断
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=7;j<=12;j++) scanf("%d",&a[j]),a[j-6]=a[j+6]=a[j];
if(insert())
{
printf("Twin snowflakes found.");
return 0;
}
}
printf("No two snowflakes are alike.");
}