您的位置:首页 > 其它

POJ 3349 Snowflake Snow Snowflakes (hash 查找)

2013-08-09 13:51 369 查看
Snowflake Snow Snowflakes

Time Limit: 4000MSMemory Limit: 65536K
Total Submissions: 27156Accepted: 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
2
1 2 3 4 5 6
4 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^------------>/article/7844314.html

这题还有一些细节,请戳这里---------->/article/1968895.html

代码:

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: