题解 SP4354 【TWINSNOW - Snowflakes】

分析

显然,对于两片形状相同的雪花,它们六个角的长度之和、长度之积都相等(注意:这并不意味着六个角的长度之和、长度之积都相等的雪花就是形状相同)。

定义 HashHash 函数:

H(ai,1,ai,2,...,ai,6)=(j=16ai,j+j=16ai,j)modPH(a_{i,1},a_{i,2},...,a_{i,6})=(\sum_{j=1}^6a_{i,j}+\prod_{j=1}^6a_{i,j})\bmod P

其中 PP 是我们自己选取的一个较大的质数,这样,两片形状相同的雪花的 HashHash 函数值也相等。

建立一个 HashHash 表,把 NN 片雪花依次插入。对于每片雪花 ai,1,ai,2,ai,6a_{i,1},a_{i,2},…a_{i,6},我们直接扫描表头 H(ai,1,ai,2,ai,6)H(a_{i,1},a_{i,2},…a_{i,6}) 对应的链表,检查是否存在与 ai,1,ai,2,ai,6a_{i,1},a_{i,2},…a_{i,6} 形状相同的雪花即可。对于随机数据,期望的时间复杂度为 O(N2/P)O(N^2/P);取 PP 为最接近 NN 的质数,期望时间复杂度为 O(N)O(N)

代码

我相信你看完我枯燥的解释就是为了这里

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100006, P = 99991;
int n, a[6], b[6];
struct S {//雪花结构体,这样方便整体赋值
	int s[6];
};
vector<S> snow[N];

int H() {//把六个角上的数转换为对应的Hash值
	int s = 0, k = 1;
	for (int i = 0; i < 6; i++) 
   {
		(s += a[i]) %= P;
		k = (ll)k * a[i] % P;
	}
	return (s + k) % P;
}

bool pd() {//判断是否相同
	for (int i = 0; i < 6; i++)
		for (int j = 0; j < 6; j++)
      {
			bool v = 1;
			for (int k = 0; k < 6; k++)
				if (a[(i+k)%6] != b[(j+k%6)]) //顺时针
           {
					v = 0;
					break;
				}
			if (v) return 1;
			v = 1;
			for (int k = 0; k < 6; k++)
				if (a[(i+k)%6] != b[(j-k+6)%6])//逆时针
           {
					v = 0;
					break;
				}
			if (v) return 1;
		}
	return 0;
}
bool insert()//插入并返回是否相同
{
	int h = H();
	for (unsigned int i = 0; i < snow[h].size(); i++) 
   {
		memcpy(b, snow[h][i].s, sizeof(b));
		if (pd()) return 1;
	}
	S s;
	memcpy(s.s, a, sizeof(s.s));
	snow[h].push_back(s);
	return 0;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++)
   {
		for (int j = 0; j < 6; j++) scanf("%d", &a[j]);
		if (insert()) 
      {
			cout << "Twin snowflakes found." << endl;
			return 0;
		}
	}
	cout << "No two snowflakes are alike." << endl;
	return 0;
}
posted @ 2021-02-08 19:36  luckydrawbox  阅读(18)  评论(0)    收藏  举报  来源