POJ-3349 Snowflake Snow Snowflakes(哈希表的数字分析法构造+链地址法处理冲突)
借鉴地址:https://blog.youkuaiyun.com/lyy289065406/article/details/6647351
Time Limit: 4000MS | Memory Limit: 65536K | |
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 by n 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
#include<iostream>
#include<stdlib.h>
#include<cstdio>
#include<string.h>
using namespace std;
#define prime 999983
struct Node1
{
long long len[6];
}snowflake[100001];
typedef struct Node2
{
long long len[6]; //记录6瓣叶子的长度信息
Node2* next;
}HashTable;
HashTable* Hash[prime+1]; //我的以后统一:HashTable 是 类的名字 ,Hash 是数组的名字。
//这个是构造哈希函数的另一种方法吧,姑且也叫数字分析法吧
long long compute_key(int k)
{
int i;
long long key=0;
for(i=0;i<6;i++)
{
key+=(snowflake[k].len[i]) % prime;
key%=prime; //利用同余模定理计算key,避免出现大数
}
return ++key; //键值后移1位,把key的范围从0~999982变为 1~999983
}
/*顺时针的话就往后推1个,逆时针的话就往前推1个*/
/*转圈圈的话肯定是要取余的啊*/
/*从顺时针方向判断两片雪花是否相同*/
bool clockwise(HashTable* p,int k)
{
int i,j;
for(j=0;j<6;j++) //顺时针转动j格
{
bool flag=true;
for( i=0;i<6;i++)
if(snowflake[k].len[i] != p->len[(i+j)%6])
{
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
/*从逆时针方向判断两片雪花是否相同*/
bool counterclockwise(HashTable* p,int k)
{
int i,j;
for(j=5;j>=0;j--) //逆时针转动j格
{
bool flag=true;
for(i=0;i<6;i++)
if(snowflake[k].len[i] != p->len[(5-i-j+6)%6]) //这里+6很漂亮,这样就没有负数的余数问题了
{ //总个数-i就是逆时针的第几个,总个数+i就是顺时针第几个。
flag=false;
break;
}
if(flag)
return true;
}
return false;
}
/*把第k个雪花信息插入HashTable*/
/*当插入的位置已存在其他雪花信息时,顺便比较*/
bool Hashinsert(int k)
{
long long key=compute_key(k);
int i;
if(Hash[key]==NULL)
{
HashTable* temp=(HashTable*)malloc(sizeof(HashTable));
for(i=0;i<6;i++)
temp->len[i]=snowflake[k].len[i];
Hash[key]=temp; //因为是临时函数,必须保存key对应的地址,不然一切白费
}
else //用链地址法处理冲突
{
HashTable* temp=Hash[key];
if(clockwise(temp,k)||counterclockwise(temp,k)) //检查雪花是否相同
return true;
while(temp->next) //链地址法就是在相同key值地址后不断连接。
{
temp=temp->next;
if(clockwise(temp,k)||counterclockwise(temp,k)) //检查雪花是否相同
return true;
}
temp=(HashTable*)malloc(sizeof(HashTable));
for(i=0;i<6;i++)
temp->len[i]=snowflake[k].len[i];
temp->next=NULL;
}
return false;
}
int main()
{
int n;
int i,j;
scanf("%d",&n);
int t=n;
while(t--)
{
memset(Hash,0,sizeof(Hash)); // 0 <-> NULL
bool flag=false; //记录输入过程中是否出现了相同的雪花
for(i=1;i<=n;i++)
{
for(j=0;j<6;j++)
scanf("%lld",&snowflake[i].len[j]);
if(!flag) //当前还没有出现相同的雪花
flag=Hashinsert(i);
//若出现相同的雪花,则还需后续输入,但不再处理
}
if(flag)
cout<<"Twin snowflakes found."<<endl;
else
cout<<"No two snowflakes are alike."<<endl;
}
return 0;
}