通过这道题要熟练掌握把数组当作链表来用的技能,这和图的邻接表的数组实现及其应用基于同样的原理。
本题题目链接Snowflake Snow Snowflakes
每个雪花都有六个分支,用六个整数代表,这六个整数是从任意一个分支开始,朝顺时针或逆时针方向遍历得到的。输入多个雪花,判断是否有形状一致的雪花存在。
简单的数字哈希,要注意的是每种雪花可以由多种数字组合表示。
比如输入的是1 2 3 4 5 6,
则2 3 4 5 6 1,3 4 5 6 1 2,……,6 5 4 3 2 1,5 4 3 2 1 6等都是相同形状的。
原文是(因此可以在读入一个雪花的时候把这些情况全部放入哈希表中)
但我给改成只插入一次雪花,而非12次。
如果某次插入的时候存在重复的雪花,那么后面的不需要再处理。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100001;
const int H = 100001;
typedef struct node{
int arm[6];
int next; //记录同哈希值的雪花的上一编号
}Node;
Node node[N];
int counter; //雪花编号,一直是累加的
int hashtable[H];
void initial_hash()
{
counter=0;
for(int i=0;i<H;i++){
hashtable[i]=-1; //前继无人
}
}
bool compare(int *arm1,int *arm2)
{
for (int i = 0; i < 6; ++i)
{
if (arm1[i] != arm2[i])
return false;
}
return true;
}
unsigned get_hash(int *arm)
{
unsigned int total=0;
for(int i=0;i<6;i++){
total+=arm[i];
}
return total % H;
}
void insert(int *arm,unsigned int h)
{
for(int i=0;i<6;i++){
node[counter].arm[i]=arm[i];
}
node[counter].next=hashtable[h];
hashtable[h]=counter++; //counter是雪花编号,一直是累加的
}
bool search(int *arm)
{
int h=get_hash(arm);
for(int i=hashtable[h];i!=-1;i=node[i].next){
if(compare(node[i].arm,arm))
return true;
}
/* 把这句挪到主函数中的循环匹配函数后,只有在匹配失败后才插入;
否则按照原来的写法,需要插入12次同样的雪花
insert(arm,h);
*/
return false;
}
int main()
{
int arm[2][11]; //不用12列,只用11列就够了
int n;
bool twin = false;
initial_hash();
scanf("%d", &n);
while (n--)
{
for (int i = 0; i < 6; ++i)
{
scanf("%d", &arm[0][i]);
arm[0][i + 6] = arm[0][i];
}
if (twin) continue; //已经匹配了之后,就不管后面的输入了
for (int i = 0; i < 6; ++i)
{
arm[1][i + 6] = arm[1][i] = arm[0][5 - i];
}
/*上面两个for循环是为了处理所有的雪花情况——顺时针、逆时针、错位等,共12种情况*/
int i;
for ( i = 0; i < 6; ++i)
{
//每一种情况(雪花的旋转)都要search,每一次search都有不定数量的compare(和同组相同哈希值的雪花进行比较)
//相同的hash值不意味着雪花相等,敌不动我动,只有待插入(比较)的雪花才旋转,已经插入的不动,等待比较
if (search(arm[0] + i) || search(arm[1] + i))
{
twin = true;
break;
}
}
if(i==6) { //没找到才插入一次(最原始的雪花)
insert(arm[0],get_hash(arm[0]));
}
}
if (twin)
printf("Twin snowflakes found.\n");
else
printf("No two snowflakes are alike.\n");
return 0;
}