POJ 3349 Snowflake Snow Snowflakes(hash哈希表)

Snowflake Snow Snowflakes
Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 38577   Accepted: 10115

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

CCC 2007



思路:

题意大体意思是,给出n个数字串,然后每个数字串可以围起来形成一个雪花圆环,(雪花从正面和反面看是方向相反的两个圆环),然后就顺序和逆序分别判断两个数字串是否完全一样。也就是,如果每个数的左右两边的元素都对应一样的话,则说明这个两个串互为雪花。但是如果每个串都判断的话,那么就需要对每个元素左右两边的数都判断是否相等,复杂度会超过n^2,所以肯定要运用别的知识——哈希表。哈希表有对应的索引值(也就是key值),然后把相同索引值的放在一起,那样的话就会舍去很多不符合索引值要求的输入值。比输入的是1 2 3 4 5 6,则2 3 4 5 6 1,3 4  5 6 1 2,……,6 5 4 3 2 1,5 4 3 2 1 6等都是相同形状的。运用哈希表的知识,每读进一片雪花,将雪花hash,判断hash表里是否有相同的hash值,有相同的hash值,从链表中一一取出并判断是否同构,是同构得出结果。然后将该雪花加入到表中,所有雪花读完也没有发现相同的,则得出结果。我这里用了除留余数法,因为这里的n(n就是指的是要判断的个数)是100000,所以取10n以内的最大素数,也就是999983。

当且仅当两片雪花的key值一样时,这两片雪花才有可能相同。在输入第k个雪花信息的时候,先求出其key值,若在hash[]中key值没有出现过,则直接存放信息。但如果在hash[key]中已经保存有其他地址,说明此前出现过key值相同的其他雪花,这些雪花信息以链表的形式存放在hash[key]中,这时在为第k个雪花信息寻找存放空间的同时,必然在链表中逐一访问这些具有相同key值得雪花,所以我们就能在寻址的同时,顺便逐一比较第k个雪花与这些雪花的信息,一旦发现k与某个雪花是一样的,则标记,然后等待后续输入完成后,直接输出寻找到两片一样的雪花。当所有输入结束后都没有标记过,则说明不存在一样的雪花。


代码:

#include<iostream> 
#include<cstdio>
#include<cstring> 
typedef long long ll;
using namespace std;  


const ll prime=999983;  // 10n内最大的素数(本题n=10W)  
  
class  
{  
public:  
    ll len[6];  //6瓣叶子的长度  
}leaf[100001];  
 
typedef class HashTable  
{  
public:  
    ll len[6];   //记录6瓣叶子的长度信息  
    HashTable* next;  //用于冲突时开放寻址  
  
    HashTable()  //Initial  
    {  
        next=0;  
    }  
}Hashtable;  
  
Hashtable* hash[prime+1];  
  
/*计算第k个雪花的关键字key*/  
  
ll compute_key(int k) 
{  
    ll key=0;  
    for(int i=0;i<6;i++)  
    {  
        key+=(leaf[k].len[i]) % prime;  
        key%=prime;   //利用同余模定理计算key,避免出现大数  
    }  
  
    return ++key;  //键值后移1位,把key的范围从0~999982变为 1~999983  
}  
  
/*从顺时针方向判断两片雪花是否相同*/  
  
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;  
}  
  
/*从逆时针方向判断两片雪花是否相同*/  
  
bool counterclockwise(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[(5-i-j+6)%6])  
            {  
                flag=false;  
                break;  
            }  
        if(flag)  
            return true;  
    }  
    return false;  
}  
  
/*把第k个雪花信息插入HashTable*/  
/*当插入的位置已存在其他雪花信息时,顺便比较*/  
  
bool insert(int k)  
{  
    ll key=compute_key(k);  
  
    if(!hash[key])  
    {  
        Hashtable* temp=new Hashtable;  
  
        for(int i=0;i<6;i++)  
            temp->len[i]=leaf[k].len[i];  
  
        hash[key]=temp;  //保存key对应的地址  
    }  
    else  //地址冲突,开放寻址,顺便比较  
    {  
        Hashtable* temp=hash[key];  
  
        if(clockwise(temp,k) || counterclockwise(temp,k))  //检查雪花是否相同  
            return true;  //比较时要把hash[key]里面的所有雪花都比较一遍 
  
        while(temp->next)    //寻址  
        {  
            temp=temp->next;  
  
            if(clockwise(temp,k) || counterclockwise(temp,k))  //检查雪花是否相同  
                return true;  
        }  
  
        temp->next=new Hashtable;    //申请空间,保存新雪花信息  
        for(int i=0;i<6;i++)  
            temp->next->len[i]=leaf[k].len[i];  
    }  
    return false;  
}  
  
int main(int i,int j)  
{  
    int n;  //雪花数  
    while(cin>>n)  
    {  
        /*Initial*/  
  
        memset(hash,0,sizeof(hash));  // 0 <-> NULL  
    
        /*Input*/  
  
        bool flag=false;  //记录输入过程中是否出现了相同的雪花  
        for(i=1;i<=n;i++)  
        {  
            for(j=0;j<6;j++)  
                scanf("%Illd",&leaf[i].len[j]);  
  
            /*Hash*/  
  
            if(!flag)    //当前还没有出现相同的雪花  
                flag=insert(i);  
                         //若出现相同的雪花,则还需后续输入,但不再处理  
        }  
  
        /*Output*/  
  
        if(flag)  
            cout<<"Twin snowflakes found."<<endl;  
        else  
            cout<<"No two snowflakes are alike."<<endl;  
  
    }  
    return 0;  
}  





全部评论

相关推荐

点赞 评论 收藏
转发
感觉这一周太梦幻了,就像一个梦,很不真实~~~感觉这个暑期,我的运气占了99成,实力只有百分之一4.15上午&nbsp;腾讯csig&nbsp;腾讯云部门,面完秒进入复试状态4.16下午&nbsp;美团优选供应链部门,4.18上午发二面4.17晚上&nbsp;阿里国际一面,纯拷打,面完我都玉玉了4.18下午&nbsp;阿里国际二面,是我们leader面的我,很轻松~~4.18晚上&nbsp;约了hr面4.19上午&nbsp;hr面,下午两点口头oc4.19晚上&nbsp;意向书说起来我的暑期好像一次都没挂过~~~~~难道我是天生面试圣体?----------------------------------------------------------------------六个月前,我还是0项目0刷题,当时想的是先把论文发出来再去找实习。结果一次组会,老师打破了我的幻想(不让投B会,只让投刊或者A)我拿头投啊!!!然后就开始物色着找实习,顺便做完了mit的6.s081,但是基本上还是没刷过题目-----------------------------------------------------------------------11月&nbsp;&nbsp;一次偶然的机会,面进了某个耳机厂的手环部门,大概是做嵌入式的,用的是CPP。12月&nbsp;莫名其妙拿到了国创的面试机会,0基础四天速成java基础!居然也给我面过了hhhhh,可能是面试没写题吧入职国创后的几个月,一直没活,天天搁那看剧,都快忘了还有暑期实习这回事了~~~~命运的齿轮在2.26开始转动,因为这一天美团开了,我开始慌了,因为那时的我什么都不会。lc,八股,sql全部是0进度。然后就开始了女娲补天,上班刷题,下班继续做之前的开源,顺便学一学八股。3月到现在,lc也刷到快200了,一天最多提交了47次~~~~~~~~~~八股根据别人的面经总结和博客,写了快十万字的笔记~~~~~~~~~~简历上的实习经历和开源,也努力去深挖了,写了几万字的记录~~~~~~所以面试的时候,基本上都能cover了,面试官问到的基础基本都会,不基础的我就把他往我会的地方引。结果好像还不错,基本上每个面试官评价都挺好的emmmmmmmm
投递阿里巴巴等公司10个岗位
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务