【可循环相等hash函数】 雪花雪花雪花
传送门
题意
有\(n\)片雪花,每片雪花有\(6\)个角,每个角都有长度,其中第\(i\)片雪花用六元组\((a_{i, 1}, a_{i, 2}, \ldots, a_{i, 6})\)表示,
例如\(a_{i, 1}, a_{i, 2}, \ldots, a_{i, 6}\)和\(a_{i, 2}, a_{i, 3}, \ldots, a_{i, 6}, a_{i, 1}\),这两个六元组就是相同的,
定义两片雪花同构当且仅当两片雪花各自分别从某一个点开始,顺时针或者逆时针后得到相同的六元组即为形状相同的雪花,
问这\(n\)片雪花中是否存在两片形状相同的雪花
数据范围
\(\begin{array}{l}1 \leq n \leq 100000 \\ 0 \leq a_{i, j}<10000000\end{array}\)
题解
-
定义\(hash\)函数为\(Hash(a_{i,1},a_{i,2},\dots,a_{i,6})=(\sum_{j=1}^{6}a_{i,j} + \Pi_{j=1}^{6})mod \; p\)
-
可以看出两个同构的雪花其\(Hash\)函数一定相等
-
\(Hash\)函数相等的两个雪花可能有某种顺序对应相等,需要再判断
-
-
判断两个\(Hash\)函数相等的雪花是否相等时,可以固定一个的起点,以及顺序
-
判断另一个雪花以所有节点为起点的顺序和逆序是否与当前的顺序相同
-
通过对\(6\)取模数可以不冲的对数列循环访问
-
-
每次插入都与\(hash\)值相同的进行比较如果比较成功可以直接结束,否则依次比较当所有都插入并且没有相等的
对于随机数据,期望的时间复杂度为\(O(\frac{N \times N}{P})\),取\(P\)为最接近\(N\)的质数,冲突的概率小,时间复杂度可以有效降低
期望的时间复杂度为\(O(N)\)
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define fi first
#define se second
#define ll long long
#define pb push_back
#define close ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
typedef pair<long long,long long> pll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<long long> vll;
typedef double db;
const ll mod=1e9+7;
const int N=1e5+10;
const int P=99991;
ll powmod(ll a,ll b,ll p)
{
ll res=1;
a%=p;
while(b)
{
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
int _;
int n;
int snow[N][6],h[N],ne[N],idx;
int Hash(int a[])
{
int sum=0,mul=1;
rep(i,0,6)
{
sum=(sum+a[i])%P;
mul=(ll)mul*a[i]%P;
}
return (sum+mul)%P;
}
bool equal(int a[],int b[])
{
rep(i,0,6)
rep(j,0,6)
{
bool f=1;
rep(k,0,6)
if(a[(i+k)%6] != b[(j+k)%6])
f=0;
if(f) return 1;
f=1;
rep(k,0,6)
if(a[(i+k)%6]!=b[(j-k+6)%6]) f=0;
if(f) return 1;
}
return 0;
}
bool insert(int a[])
{
int val = Hash(a);
for(int i=h[val];i;i=ne[i])
if(equal(snow[i],a)) return 1;
++idx;
memcpy(snow[idx],a,6*sizeof(int));
ne[idx]=h[val];
h[val]=idx;
return 0;
}
void solve()
{
cin>>n;
rep(i,0,n)
{
int a[10];
rep(j,0,6) cin>>a[j];
if(insert(a))
{
cout<<"Twin snowflakes found."<<endl;
return;
}
}
cout<<"No two snowflakes are alike."<<endl;
}
int main(){
close;
solve();
}

浙公网安备 33010602011771号