思路 :题目有两种操作方法,一种为旋转,一种为翻转。两种都取最小字典序的排列,取最小。
对比每个雪花的最小字典序相同则雪花相同。
所用技巧:
哈希表——将雪花相同映射为最小字典序相同(最小字典序是唯一的其相同则雪花相同)
求最小字典序的简易方法即代码中的get_min.
取两指针j = 1 ,i = 0偏移值k = 0。欲求a数组的最小字典序即将两个a数组拼接在一起形成一个b数组前六个中不管从哪个开始就类比于旋转。当a[i] == a[j]时偏移量加一直到有一方较大。较大者偏移量前的都不会取到i += k + 1。如果偏移量 == n则全数组相等。直到i == 6 || j == 6
最后取min(i, j)
代码如下:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
int snows[N][6], idx[N];
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]){
j += k + 1;
else{
i += k + 1;
}
if(i == j) i ++;//将i于j错位
}
k = min(i, j);
for(int i = 0;i < 6;i ++){
a[i] = b[i + k];
}
}
bool cmp(int a[],int b[]){
for(int i = 0;i < 6;i ++){
if(a[i] < b[i]) return true;
if(a[i] > b[i]) return false;
}
return false;
}
bool cmp2(int a, int b){
for(int i = 0;i < 6;i ++){
if(snows[a][i] < snows[b][i]) return true;
if(snows[a][i] > snows[b][i]) return false;
}
return false;
}
int main(){
int n;
int snow[6], isnow[6];
scanf("%d",&n);
for(int i = 0; i < n; i ++){
for(int j = 0;j < 6; j ++){
scanf("%d", &snow[j]);
isnow[5 - j] = snow[j];
}
get_min(snow);
get_min(isnow);
if(cmp(snow, isnow)) memcpy(snows[i], snow, sizeof snow);
else memcpy(snows[i], isnow, sizeof isnow);
idx[i] = i;// 开这个的用处在于可以使用sort排序二维数组
}
sort(idx, idx + n, cmp2);
for(int i = 1;i < n;i ++){
if(!cmp2(idx[i], idx[i - 1]) && !cmp2(idx[i - 1], idx[i])){
puts("Twin snowflakes found.");
return 0;
}
}
puts("No two snowflakes are alike.");
return 0;
}