POJ3349【hash应用】【被输入外挂坑好久】【hash No.1】

大致题意:

在n (n<100000)个雪花中判断是否存在两片完全相同的雪花,每片雪花有6个角,每个角的长度限制为1000000

两片雪花相等的条件:

雪花6个角的长度按顺序相等(这个顺序即可以是顺时针的也可以是逆时针的)

 

然后我这一下午就陷入无尽的TLE当中了。

 

过程总结~

 

1。抛开题意理解不说。

    (以后绝不能看题解理解题意了,必须提高自己的英文阅读理解能力。)

       自己一开始用了LRJ的输入外挂,到最后才知道是输入外挂坑了自己。

       貌似POJ不识别cctype.h,以后自己尽量用Scan()了。

       然后自己一开始建的哈希是直接所有的数加起来取和,由于坑在输入外挂上,并不知这样做的错误。只是建这么大的内存会Memory Limit exceeded;

      所以也体会到他们建哈希MOD一个大素数的原由了,后来改为取余大素数就过了。

 

2.。关于HASH现在自己敢说原理是比较明白了。

     建哈希处理冲突的方法运用链表。这题顺便帮自己复习了一下链表。

 

3。题意理解

      老是丢条件的习惯不好。顺时针or逆时针比较!!

      顺便附上比较快速的比较方法。

  1. /*从顺时针方向判断两片雪花是否相同*/
  2. bool clockwise(Hashtable* p,int k)
  3. {
  4. for(int j=0;j<6;j++)//顺时针转动j格
  5. {
  6. bool flag=true;
  7. for(int i=0;i<6;i++)
  8. if(leaf[k].len[i] != p->len[(i+j)%6])
  9. {
  10. flag=false;
  11. break;
  12. }
  13. if(flag)
  14. return true;
  15. }
  16. return false;
  17. }

在这里给出两条公式:

设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;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值