POJ 3349 Snowflake Snow Snowflakes (hash 查找)

来源:互联网 发布:阿里设置一键上传淘宝 编辑:程序博客网 时间:2024/05/15 02:21
Snowflake Snow Snowflakes
Time Limit: 4000MS Memory Limit: 65536KTotal Submissions: 27156 Accepted: 7156

Description

You may have heard that no two snowflakes are alike. Your task is to write a program to determine whether this is really true. Your program will read information about a collection of snowflakes, and search for a pair that may be identical. Each snowflake has six arms. For each snowflake, your program will be provided with a measurement of the length of each of the six arms. Any pair of snowflakes which have the same lengths of corresponding arms should be flagged by your program as possibly identical.

Input

The first line of input will contain a single integer n, 0 < n ≤ 100000, the number of snowflakes to follow. This will be followed byn lines, each describing a snowflake. Each snowflake will be described by a line containing six integers (each integer is at least 0 and less than 10000000), the lengths of the arms of the snow ake. The lengths of the arms will be given in order around the snowflake (either clockwise or counterclockwise), but they may begin with any of the six arms. For example, the same snowflake could be described as 1 2 3 4 5 6 or 4 3 2 1 6 5.

Output

If all of the snowflakes are distinct, your program should print the message:
No two snowflakes are alike.
If there is a pair of possibly identical snow akes, your program should print the message:
Twin snowflakes found.

Sample Input

21 2 3 4 5 64 3 2 1 6 5

Sample Output

Twin snowflakes found.

Source

CCC 2007

题意:给n个雪花,每个雪花有6个角,如果6个角的长度对应(顺时针或逆时针)相等,则两片雪花相同。题目要找N个雪花中有没有相同的雪花。

分析:

Hash吧!连加求余法 求key 值,链地址法解决冲突

设雪花6片叶子的长度为len1~len6

key=( len1+len2+len3+len4+len5+len6)%prime

   =( len1%prime +len2%prime +len3%prime +len4%prime +len5%prime +len6)%prime

为了避免出现大数,这里使用了同余模定理求key

 

注意,这里的key千万不能用平方和,本来这题时间就很紧凑了,乘法运算更加严重浪费时间,所以采用了连加求key,只要mod足够大,同样能够把地址冲突降低到最低,我取了10n(就是100W)内的最大的素数作为mod,  mod=999983

 

设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 )

 

关于基本的hash查找学习,请戳这里^3^------------>http://blog.csdn.net/u011262722/article/details/9851719

这题还有一些细节,请戳这里---------->http://blog.csdn.net/lyy289065406/article/details/6647351

 

代码:

#include<cstdio>#include<iostream>#include<cstring>const __int64 mod=999983;using namespace std;typedef class HashTable{    public:        __int64 len[6];      //记录6个角的长度        HashTable *next;     //用于冲突时在链表中寻址        HashTable()        {            next=0;        }}Hashtable;class snow{    public:        __int64 len[6];       //6个角的长度}leaf[100005];Hashtable *hash[mod+1];__int64 compute_key(int k)   //算第k个雪花的关键字{    __int64 key=0;    for(int i=0;i<6;i++)    {        key+=(leaf[k].len[i])%mod;        key=key%mod;         //利用同余模定理,避免出现大数    }    return ++key;            //键值后移1位,把key的范围从0~999982变为 1~999983}bool clockwise(Hashtable *p,int k)  //顺时针判断两个雪花是否相同{    for(int i=0;i<6;i++)        //顺时针转动i次    {        bool flag=true;        for(int j=0;j<6;j++)        {            if(leaf[k].len[j]!=p->len[(i+j)%6])            {                flag=false;                break;            }        }        if(flag)            return true;    }    return false;}bool counterclockwise(Hashtable *p,int k)   //逆时针判断两个雪花是否相同{    for(int i=0;i<6;i++)           //逆时针转动i次    {        bool flag=true;        for(int j=0;j<6;j++)        {            if(leaf[k].len[j]!=p->len[(5-i-j+6)%6])            {                flag=false;                break;            }        }        if(flag)            return true;    }    return false;}//把第k个雪花信息插入HashTable //当插入的位置已存在其他雪花信息时,顺便比较bool Inserthash(int k){    __int64 key=compute_key(k);    if(!hash[key])    {        Hashtable *tmp=new Hashtable;        for(int i=0;i<6;i++)            tmp->len[i]=leaf[k].len[i];        hash[key]=tmp;       //保存key对应的地址    }    else     //地址冲突,寻址并比较    {        Hashtable *t=hash[key];        if(clockwise(t,k) || counterclockwise(t,k))            return true;        //else        //{            while(t->next)    //向后寻址            {                t=t->next;                if(clockwise(t,k) || counterclockwise(t,k))   //判断雪花是否相同                    return true;            }            t->next=new Hashtable;     //申请空间,保存新的雪花信息            for(int i=0;i<6;i++)                t->next->len[i]=leaf[k].len[i];        //}    }    return false;}int main(){    int i,j,n;    while(scanf("%d",&n)!=EOF)    {        memset(hash,0,sizeof(hash));        bool flag=false;         //记录输入过程中是否出现了相同的雪花        for(i=1;i<=n;i++)        {            for(j=0;j<6;j++)                scanf("%I64d",&leaf[i].len[j]);            if(!flag)              //如果还没出现相同的雪花                flag=Inserthash(i);         }              //如果出现了相同的雪花,继续后面的输入,但不对其做处理。        if(flag)            printf("Twin snowflakes found.\n");        else            printf("No two snowflakes are alike.\n");    }    return 0;}


 

 

11948135

fukan

3349

Accepted

16624K

3797MS

C++

2486B

2013-08-09 10:52:46

 

 

 

原创粉丝点击