AcWing 137. 雪花雪花雪花
考察:hash+字符串的最大最小表示法
通过这道题发现之前的最小最大表示法可以从1开始还不用写三元表达式,就是之前的断环成链思想,这种取余的又要下标从1开始还是断环成链比较方便
关于这道题写写对于hash的思考
- 字符串hash多用于已知长度的字符串,下标是字符串的下标,hash值不允许为0
- 散列表hash的下标与值有关,是值的一个映射,有开放地址法和拉链法存储避免冲突
- 开放地址法的数组大小通常开到接近序列大小2~3倍的质数(将值映射到0~该质数),hash值允许为0
- 拉链法接近正常大小的质数即可
- 利用开放地址法最重要的是避免冲突,尽量选择好的方法减少冲突
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 }