AcWing 137. 雪花雪花雪花

原题链接

考察:hash+字符串的最大最小表示法

通过这道题发现之前的最小最大表示法可以从1开始还不用写三元表达式,就是之前的断环成链思想,这种取余的又要下标从1开始还是断环成链比较方便

关于这道题写写对于hash的思考

  1. 字符串hash多用于已知长度的字符串,下标是字符串的下标,hash值不允许为0
  2. 散列表hash的下标与值有关,是值的一个映射,有开放地址法和拉链法存储避免冲突
  3. 开放地址法的数组大小通常开到接近序列大小2~3倍的质数(将值映射到0~该质数),hash值允许为0
  4. 拉链法接近正常大小的质数即可
  5. 利用开放地址法最重要的是避免冲突,尽量选择好的方法减少冲突
 1 #include <iostream>
 2 #include <cstring>
 3 #include <unordered_map>
 4 using namespace std;
 5 typedef unsigned long long ull;
 6 const int P = 131;
 7 const int N = 100010;
 8 int snow[N][15];//雪花,存放每个雪花的最小表示
 9 unordered_map<ull,int> um;
10 bool cmparr(int a[],int b[])
11 {
12     for(int i=1;i<=6;i++){
13         if(a[i]>b[i]) return false;
14         if(a[i]<b[i]) return true;
15     }
16     return true;
17 }
18 void Getmins(int a[])
19 {
20     for(int i=7;i<=12;i++) a[i] = a[i-6];
21     int i=1,j=2,k;
22     while(i<=6&&j<=6){
23         for(k=0;k<6&&a[i+k]==a[j+k];k++);
24         if(k==6) break;//已经达到新的循环节
25         if(a[i+k]>a[j+k]){
26             i = i+k+1;
27             if(i==j) i++;
28         }else if(a[i+k]<a[j+k]){
29             j = j+k+1;
30             if(i==j) j++;
31         }
32     }
33     int ans = min(i,j);
34     for(int i=1;i<=6;i++) a[i] = a[ans+i-1];//ans的作用使ans+i-1比i大,所以不会出现覆盖现象
35 }
36 int main()
37 {
38     int n;
39     scanf("%d",&n);
40     for(int i=1;i<=n;i++){
41         int rnow[15];
42         for(int j=1;j<=6;j++){
43             scanf("%d",&snow[i][j]);
44             rnow[7-j] = snow[i][j];
45         }
46         Getmins(snow[i]);
47         Getmins(rnow);
48         if(!cmparr(snow[i],rnow)) memcpy(snow[i],rnow,sizeof(rnow));
49         ull h = 0;
50         for(int j=1;j<=6;j++) h = h*P+snow[i][j];
51         if(!um[h]) um[h]++;
52         else{
53             cout << "Twin snowflakes found.";
54             return 0;
55         }
56     }
57     cout<<"No two snowflakes are alike."<<endl;
58     return 0;
59 }

 

posted @ 2021-01-07 02:01  acmloser  阅读(172)  评论(0编辑  收藏  举报