雪花雪花雪花
思路:雪花六个角,通过旋转和翻转后能不能匹配到相同的两种排列,如果有,就代表两者相同,否则不同。其实可以简化为将两种排列进行旋转和翻转后得到两种最小的字典序排列,如果两者最小字典序排列相同,就证明两个相同。翻转可以分为奇数和偶数次奇数次相当于翻转一次,偶数次相当于没有翻转。实质上只用在一开始就储存原排列的时候进行翻转一次后另外储存,再进行旋转找最小字典序排列进行比较即可。
题解1:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int n;
int snows[N][6], idx[N];
//判断两个数组的字典序(利用O(n)的复杂度进行查找最小的字典序排列)
bool cmp_array(int a[],int b[])
{
for (int i = 0; i < 6;i++){
if(a[i]>b[i])
return 0;
else if(a[i]<b[i])
return 1;
}
return 0;
}
//判断以a,b所在位置为起点的排列是否相同
bool cmp(int a,int b)
{
return cmp_array(snows[a], snows[b]);
}
//找字典序最小的排列
void get_min(int a[])
{
static int b[12];
for (int i = 0; i < 12;i++)
b[i] = a[i % 6];
int i = 0, j = 1, k;
while(i<6&&j<6)
{
for (k = 0; k < 6 && b[i + k] == b[j + k];k++);
if(k==6)
break;
if(b[i+k]>b[j+k])
{
i += k + 1;
if(i==j)
i++;
}
else{
j += k + 1;
if(i==j)
j++;
}
}
k = min(i, j);
for (i = 0; i < 6;i++)
a[i] = b[i + k];
}
int main()
{
scanf("%d", &n);
int snow[6], isnow[6];//原雪花和翻转后的雪花
for (int i = 0; i < n;i++){
for (int j = 0, k = 5; j < 6;j++,k--){
scanf("%d", &snow[j]);
isnow[k] = snow[j];
}
get_min(snow);//找到以原雪花为主序列的旋转后能够得到的字典序最小的排列
get_min(isnow);//找到以翻转后的雪花为主序列的旋转后能够得到的字典序最小的排列
if(cmp_array(snow,isnow))
memcpy(snows[i], snow, sizeof snow);
else
memcpy(snows[i], isnow, sizeof isnow);
idx[i] = i;
}
sort(idx, idx + n, cmp);
bool flag = 0;
for (int i = 1; i < n;i++){
if(!cmp(idx[i-1],idx[i])&&!cmp(idx[i],idx[i-1])){
flag = 1;
break;
}
}
if (flag)
puts("Twin snowflakes found.");
else
puts("No two snowflakes are alike.");
return 0;
}
思路:如果两个排列相同,那么两者的和与积之和一定相等。先设置一个比较大的质数作为哈希表的大小,方便将数据储存以便能够通过某种映射关系以O(1)的复杂度查找到该数据。
题解2:
Hash表
#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int n, tot, p = 99991, snow[N][6], head[N], Next[N];//建立链表。每次查找直接查找表头即可
//返回该情况的和与积之和
int Hash(int a[])
{
int sum = 0, mul = 1;
for (int i = 0; i < 6;i++){
sum = (sum + a[i]) % p;
mul = (long long)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 eq = 1;
for (int k = 0; k < 6;k++)
if(a[(i+k)%6]!=b[(j+k)%6])
eq = 0;
if(eq)
return 1;
eq = 1;
for (int k = 0; k < 6;k++)
if(a[(i+k)%6]!=b[(j-k+6)%6])
eq = 0;
if(eq)
return 1;
}
}
return 0;
}
bool insert(int a[])
{
int val = Hash(a);
for (int i = head[val]; i;i=Next[i])
if(equal(snow[i],a))
return 1;
++tot;
memcpy(snow[tot], a, 6 * sizeof(int));
Next[tot] = head[val];
head[val] = tot;
return 0;
}
int main()
{
cin >> n;
for (int i = 1; i < 6;i++){
int a[10];
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;
}