大致题意:
在n (n<100000)个雪花中判断是否存在两片完全相同的雪花,每片雪花有6个角,每个角的长度限制为1000000
两片雪花相等的条件:
雪花6个角的长度按顺序相等(这个顺序即可以是顺时针的也可以是逆时针的)
然后我这一下午就陷入无尽的TLE当中了。
过程总结~
1。抛开题意理解不说。
(以后绝不能看题解理解题意了,必须提高自己的英文阅读理解能力。)
自己一开始用了LRJ的输入外挂,到最后才知道是输入外挂坑了自己。
貌似POJ不识别cctype.h,以后自己尽量用Scan()了。
然后自己一开始建的哈希是直接所有的数加起来取和,由于坑在输入外挂上,并不知这样做的错误。只是建这么大的内存会Memory Limit exceeded;
所以也体会到他们建哈希MOD一个大素数的原由了,后来改为取余大素数就过了。
2.。关于HASH现在自己敢说原理是比较明白了。
建哈希处理冲突的方法运用链表。这题顺便帮自己复习了一下链表。
3。题意理解
老是丢条件的习惯不好。顺时针or逆时针比较!!
顺便附上比较快速的比较方法。
- /*从顺时针方向判断两片雪花是否相同*/
- bool clockwise(Hashtable* p,int k)
- {
- for(int j=0;j<6;j++)//顺时针转动j格
- {
- bool flag=true;
- for(int i=0;i<6;i++)
- if(leaf[k].len[i] != p->len[(i+j)%6])
- {
- flag=false;
- break;
- }
- if(flag)
- return true;
- }
- return false;
- }
在这里给出两条公式:
设i为A、B的第i片叶子,j为B当前顺时针转过的格数
那么 A(i) ---> B( (i+j)%6 )
设i为A、B的第i片叶子,j为B当前逆时针转过的格数
那么 A(i) ---> B( (5-i-j+6)%6 )
这两条公式记住吧。以后很有可能会用到。虽然感觉自己还是写不出来的样子。
4.memcpy,memcmp(a,b,5)的用法。
5.学到的牛人HASH建法。
1. 直接相加, 把(总和%大质数)为key.
2. 平方和相加, 把(总和%大质数)为key.
3. 从小到大的顺序, 对v[i]<<(i*3)依次异或, 然后模一个大质数作为key.(by hust07p43)
4. 六个数中非零数的积再乘上一个大质数,然后模一个100w上下的数。自己拿随机数据测下来110w左右的效果最好,随机情况下数据量是10w的时候hash值相同的情况只有6k多个,几乎可以忽略。(by killertom)
5. 依次对每个数异或所得的数作为key. (by archerstarlee)6. (a[0] + a[2] + a[4])&(a[1] + a[3] + a[5]), 再模一个大质数. 中间的&还可以改成'|' 或者'^'.非常巧妙! 我采用'^'得到最快的719ms. (只对本题适用的hash方法)
其实最关键的就是要开放式寻址解决hash冲突, 不要以为hash就能解决问题了.最后就是用getchar和gets来进行输入转换更为快速. G++比GCC快一些.欢迎大家补充自己更为快速的Hash方法.
6.附代码
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int prime=999983;//开1000000的数组果然也有区别哪
int a[100005][10];
//输入加速用法 n=readint();//万事自己写难//写HASH链表试一下//克制自己看题解
int hash[prime];
//数组最大开多少呃
typedef struct Node
{
int value;
struct Node *next;//我TMD还用这样建链表啊//题意理解有问题。 以后多加注意题意。
}hehe;
hehe *node[prime];
int compute_key(int k)
{
int key=0;
for(int i=0;i<6;i++)
{
key+=(a[k][i])%prime;
key%=prime; //利用同余模定理计算key,避免出现大数
}
return ++key; //键值后移1位,把key的范围从0~999982变为 1~999983
}
inline int readint()
{
char c=getchar();
while(!isdigit(c)) c=getchar();
int x=0;
while(isdigit(c))
{
x=x*10+c-'0';
c=getchar();
}
return x;
}
int buf[10];
int compare1(int *a,int *b)
{
for(int j=0;j<6;j++) //顺时针转动j格
{
bool flag=true;
for(int i=0;i<6;i++)
if(a[i]!=b[(i+j)%6])
{
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
/*从顺时针方向判断两片雪花是否相同*/
bool compare2(int *a,int *b)
{
for(int j=0;j<6;j++) //逆时针转动j格
{
bool flag=true;
for(int i=0;i<6;i++)
if(a[i]!=b[(5-i-j+6)%6])
{
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int flag=0;
for(int i=0;i<n;i++)
{
// int sum=0;
for(int j=0;j<6;j++)
scanf("%d",&a[i][j]);
if(flag==0)
{
int sum=compute_key(i);
if(!hash[sum])
{
hash[sum]=1;
node[sum]=(hehe*)malloc(sizeof(hehe));
node[sum]->value=i;
node[sum]->next=NULL;
}
else
{
hehe*u=(hehe*)malloc(sizeof(hehe));
u=node[sum];
while(u!=NULL)
{
if(compare1(a[u->value],a[i])||compare2(a[u->value],a[i]))
{flag=1;break;}
u=u->next;
}
u=(hehe*)malloc(sizeof(hehe));
u->value=i;
//u->next=NULL;
}
}
}
if(flag==1)
printf("Twin snowflakes found.\n");
else
printf("No two snowflakes are alike.\n");
}
return 0;
}