雪花雪花雪花

0x14 Hash - 图1 片雪花,每片雪花由六个角组成,每个角都有长度。
0x14 Hash - 图2 片雪花六个角的长度从某个角开始顺时针依次记为 0x14 Hash - 图3
因为雪花的形状是封闭的环形,所以从任何一个角开始顺时针或逆时针往后记录长度,得到的六元组都代表形状相同的雪花。
例如 0x14 Hash - 图40x14 Hash - 图5 就是形状相同的雪花。
0x14 Hash - 图60x14 Hash - 图7 也是形状相同的雪花。
我们称两片雪花形状相同,当且仅当它们各自从某一角开始顺时针或逆时针记录长度,能得到两个相同的六元组。
求这 0x14 Hash - 图8 片雪花中是否存在两片形状相同的雪花。
输入格式
第一行输入一个整数 0x14 Hash - 图9,代表雪花的数量。
接下来 0x14 Hash - 图10 行,每行描述一片雪花。
每行包含 0x14 Hash - 图11 个整数,分别代表雪花的六个角的长度(这六个数即为从雪花的随机一个角顺时针或逆时针记录长度得到)。
同行数值之间,用空格隔开。
输出格式
如果不存在两片形状相同的雪花,则输出:
No two snowflakes are alike.
如果存在两片形状相同的雪花,则输出:
Twin snowflakes found.
数据范围
0x14 Hash - 图12,
0x14 Hash - 图13
输入样例:

  1. 2
  2. 1 2 3 4 5 6
  3. 4 3 2 1 6 5

输出样例:

  1. Twin snowflakes found.

设计一个哈希函数,尽可能的降低碰撞率。

  1. const int P = 99991;
  2. int H(){
  3. int sum = 0,mul = 1;
  4. for(int i=0;i<6;i++){
  5. sum = (sum + a[i]) % P;
  6. mul = 1ll * mul * a[i] % P;
  7. }
  8. return (sum + mul) % P;
  9. }

上述哈希函数对雪花中的 6 个值的和与积加起来取模。为什么 P = 99991,因为这是一个不怎么大的质数,可以方便的用数组去存每一个雪花。
因此,计算每个雪花的哈希值,并插入该哈希值对应的链表中去。如果链表中已有雪花,那么就一一对比看是否存在两个一样的雪花。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 100010;
  4. int n,tot,P = 99991;
  5. int snow[N][6],head[N],nxt[N];
  6. int a[6];
  7. int H(){
  8. int sum = 0,mul = 1;
  9. for(int i=0;i<6;i++){
  10. sum = (sum + a[i]) % P;
  11. mul = 1ll * mul * a[i] % P;
  12. }
  13. return (sum + mul) % P;
  14. }
  15. bool equal(int *a,int *b){
  16. for(int i=0;i<6;i++){
  17. for(int j=0;j<6;j++){
  18. bool eq = 1;
  19. for(int k = 0;k < 6;k++){
  20. if(a[(i+k) % 6] != b[(j+k) % 6]) eq = 0;
  21. }
  22. if(eq)return 1;
  23. eq = 1;
  24. for(int k = 0;k < 6;k++){
  25. if(a[(i+k) % 6] != b[(j - k + 6) % 6])eq = 0;
  26. }
  27. if(eq)return 1;
  28. }
  29. }
  30. return 0;
  31. }
  32. bool insert(){
  33. int val = H();
  34. //cout << val << endl;
  35. for(int i=head[val];i;i=nxt[i]){
  36. if(equal(snow[i],a))return 1;
  37. }
  38. ++tot;
  39. memcpy(snow[tot],a,6 * sizeof(int));
  40. nxt[tot] = head[val];
  41. head[val] = tot;
  42. return 0;
  43. }
  44. int main(){
  45. scanf("%d",&n);
  46. for(int i=1;i<=n;i++){
  47. for(int j=0;j<6;j++)
  48. scanf("%d",&a[j]);
  49. if(insert()){
  50. puts("Twin snowflakes found.");
  51. return 0;
  52. }
  53. }
  54. puts("No two snowflakes are alike.");
  55. return 0;
  56. }

另外一种实现风格,采用 STL 中的 array 对象,并结合 unordered_map 哈希表。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. #define rep(i,j,k) for(int i=int(j);i<=int(k);i++)
  4. #define per(i,j,k) for(int i=int(j);i>=int(k);i--)
  5. typedef long long ll;
  6. const int N = 100010, P = 99991;
  7. int n;
  8. array<int, 6> a;
  9. unordered_map<int, vector<array<int, 6>>> mp;
  10. int H(){
  11. int sum = 0, mul = 1;
  12. for(int i = 0; i < 6; i++){
  13. sum = (sum + a[i]) % P;
  14. mul = 1ll * mul * a[i] % P;
  15. }
  16. return (sum + mul) % P;
  17. }
  18. bool equal(array<int, 6> &a, array<int, 6> &b) {
  19. rep(i, 0, 5) {
  20. rep(j, 0, 5) {
  21. bool eq = true;
  22. rep(k, 0, 5) {
  23. if(a[(i + k) % 6] != b[(j + k) % 6]) eq = false;
  24. }
  25. if(eq) return true;
  26. eq = true;
  27. rep(k, 0, 5) {
  28. if(a[(i + k) % 6] != b[(j - k + 6) % 6]) eq = false;
  29. }
  30. if(eq) return true;
  31. }
  32. }
  33. return false;
  34. }
  35. bool insert() {
  36. int val = H();
  37. for(auto &b : mp[val]) {
  38. if(equal(a, b)) return true;
  39. }
  40. mp[val].emplace_back(a);
  41. return false;
  42. }
  43. int main(){
  44. scanf("%d", &n);
  45. rep(i, 1, n) {
  46. rep(j, 0, 5) scanf("%d", &a[j]);
  47. if(insert()){
  48. puts("Twin snowflakes found.");
  49. return 0;
  50. }
  51. }
  52. puts("No two snowflakes are alike.");
  53. return 0;
  54. }