这道题用哈希做了好久,用哈希函数做的时候WA,用哈希表做的时候超时,最后用最小表示法查同的方法来做。
最小表示法:
从一个序列中找出以不同元素为起点组成的新序列中的字典序最小序列。
设i=0,j=1,k=0;
比较a[i+k]与a[j+k]的大小;
当a[i+k]==a[j+k]时 k++;
当a[i+k]>a[j+k]时,i=i+k+1; 因为从i->i+k开始到i+k组成的前缀必定小于某个t开始到组成的前缀.
证明;
即证 1.从i->i+k开始到i+k组成的前缀不可能是最小表示
2.从i->i+k开始到i+k组成的前缀小于从j->j+k开始到j+k组成的前缀
若2成立,证明1也成立
所以证明2:
任选i', i<=i'<=i+k+1, j<=j'<=j+k+1,显然从i'->i'+k开始到i'+k组成的前缀小于从j'->j'+k开始到j'+k组成的前缀
所以2得证
所以从i->i+k开始到i+k组成的前缀必定小于某个t开始到组成的前缀.
当a[i+k]<a[j+k]时,j=j+k+1;证明同上略
当i==len时返回i,j中小于len的那个值,就是最小表示的起点.另外当i=j时,移动的那个指针需要+1;
可以有更好的优化,当需要指针i,j滑动时,如果i+k+1小于j,可以让i直接跳到j+1,因为已证明j到j+k的前缀比之前i到i+k的前缀都要小.
最小表示法代码
int MinimumRepresentation(int *a, int len)
{
int i, j, k=0;
i=0;j=1;
while(i<len && j<len)
{
k=0;
while(k<len && a[i+k]==a[j+k])k++;
if(k==len)return i;
if(a[i+k]<a[j+k])
{
if(j+k+1<=i)j=i+1;
else j=j+k+1;
}
else
{
if(i+k+1<=j)i=j+1;
else i=i+k+1;
}
}
if(i>=len)return j;
else return i;
}
题解代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int MinimumRepresentation(int *a, int len)
{
int i, j, k=0;
i=0;j=1;
while(i<len && j<len)
{
k=0;
while(k<len && a[i+k]==a[j+k])k++;
if(k==len)return i;
if(a[i+k]<a[j+k])
{
if(j+k+1<=i)j=i+1;
else j=j+k+1;
}
else
{
if(i+k+1<=j)i=j+1;
else i=i+k+1;
}
}
if(i>=len)return j;
else return i;
}
struct p
{
int b[7];
}a[101234];
int cmp(p a, p b) // 根据字典序排序
{
int i=0;
while(i< 6 && a.b[i]==b.b[i])i++;
return a.b[i]<b.b[i];
}
int cmp2(p a, p b) //比较是否相同
{
int i=0;
while(i<6 && a.b[i]==b.b[i])i++;
if(i==6)return 1;
else return 0;
}
int main()
{
int n;
scanf("%d", &n);
int i, j;
int c[7];
int d[7];
int k, e=0;
for(i=0; i<n; i++)
{
for(j=0; j<6; j++)
{
scanf("%d", &c[j]);
d[5-j]=c[j];
}
j=MinimumRepresentation(c,6);
for(k=0; k<6; k++)
{
a[e].b[k]=c[j];
j++;
if(j==6)j=0;
}
e++;
j=MinimumRepresentation(d, 6);
for(k=0; k<6; k++)
{
a[e].b[k]=d[j];
j++;
if(j==6)j=0;
}
if(cmp(a[e-1], a[e]));
else
{
for(k=0; k<6; k++)
{
a[e-1].b[k]=a[e].b[k];
}
}
}
sort(a, a+e, cmp);
for(i=0; i<e-1; i++)
{
if(cmp2(a[i], a[i+1]))break; //相同则退出.
}
if(i<e-1)printf("Twin snowflakes found.\n");
else printf("No two snowflakes are alike.\n");
return 0;
}