题意:给你n个六个数的序列,每一个序列代表一朵雪花,问这n个雪花中存不存相同的雪花,若存在输出Twin snowflakes found.,否则输出No two snowflakes are alike.
分析: 在每输入一朵雪花,就在哈希表当中查找是否存在相同雪花,因为雪花可以旋转,所以我们要旋转查找六次,若没有找到则将这多雪花的正反两面插入哈希表中,直到输入结束。这题用在poj上用vector超时,换静态链A了,想偷懒都不行- -!。
刚开始在南阳做的这题,是想旋转查找十二次,只插入正面的雪花,果断TLE;后来旋转查找六次,插入正反两面就A了。之后在poj上一交,再次TLE。。。,把用vector写的哈希表替换成静态链 AC~。
后来想是否可以每次把最小的一个旋转到第一个位置,这样只用查找一次便可以了,改完南阳上AC,poj上WA,想了好久想不明白为什么会WA。经别人提醒发现若存在几个最小值,我只查找一次有些情况是会查找不到的,最后统计出相同最小值的数量cn,然后旋转查找cn次,每次将每个最小值都在第一个位置的情况插入哈希表,最后用时比旋转查找六次稍微少一点。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
struct node{
int key;
int v[6];
int next;
node(){}
node(int _key, int *a, int _next){
key = _key;
for(int i = 0; i < 6; i++)
v[i] = a[i];
next = _next;
}
};
const int maxn = 100005;
const int mod = 100007;
int n;
int list[mod];//hash表
node c[maxn*2];//静态链
int cnt;
int a[6];
void shift(){
int t = a[0];
for(int i = 0; i < 5; i++)
a[i] = a[i+1];
a[5] = t;
}
void reverse(){
for(int i = 0; i < 3; i++){
int t = a[i];
a[i] = a[6-i-1];
a[6-i-1] = t;
}
}
int hash_key(){
int sum = 0;
for(int i = 0; i < 6; i++){
sum += a[i];
}
return sum;
}
void hash_insert(int key, int i){
int index = key % mod;
c[i] = node(key,a,list[index]);
list[index] = i;
}
bool hash_find(int key){
int index = key % mod;
for(int i = list[index]; i != -1; i = c[i].next){
if(c[i].key == key){
bool f = true;
for(int j = 0; j < 6; j++){
if(a[j] != c[i].v[j]){
f = false; break;
}
}
if(f) return true;
}
}
return false;
}
int main(){
bool f = false;
scanf("%d",&n);
cnt = 0;
for(int i = 0; i < mod; i++) list[i] = -1;
for(int i = 0; i < n; i++){
for(int j = 0; j < 6; j++)
scanf("%d",&a[j]);
if(!f){//如果没找到
//旋转六次
for(int i = 0; i < 6; i++){
if(hash_find(hash_key())){
f = true; break;
}
shift();
}
if(!f) {
hash_insert(hash_key(),cnt++);
reverse();//翻转
hash_insert(hash_key(),cnt++);
}
}
}//end of for i to n
puts(f?"Twin snowflakes found.":"No two snowflakes are alike.");
return 0;
}