POJ 3349 Snowflake Snow Snowflakes(hash哈希表)

来源:互联网 发布:人工智能基础 知乎 编辑:程序博客网 时间:2024/05/29 06:57
Snowflake Snow Snowflakes
Time Limit: 4000MS Memory Limit: 65536KTotal 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

21 2 3 4 5 64 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;  }  





0 0
原创粉丝点击