题意:给出n个雪花的六条边的长度,求出是否有两个相同的雪花,即边的大小和顺序相同。
因为只要考虑是否存在相同的雪花,结合雪花边长可能较大的条件,考虑哈希。
需要顺时针和逆时针枚举比较。
PS:用了读入优化,然而还是3500ms飘过。。。
先贴上这份代码,优化在后面。
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int mod = 1e6 + 7;
const int maxn = 1e5 + 1;
int n;
int hash[mod];
int flag = 0;
struct node {
int tag;
int a[6];
} snow[maxn];
inline int Hash(node u) {
int t = 0;
for (int i = 0; i < 6; i++) t += u.a[i];
return t % mod;
}
inline bool clockwise(node u, node v) {
bool sig;
for (int i = 0; i < 6; i++) {
sig = 0;
int p = i;
for (int j = 0; j < 6; j++) {
if (u.a[p] != v.a[j]) {
sig = 1;
break;
}
p = (p + 1) % 6;
}
if (!sig) break;
}
if (!sig) return true;
return false;
}
inline bool counterClockwise(node u, node v) {
bool sig;
for (int i = 0; i < 6; i++) {
sig = 0;
int p = i;
for (int j = 0; j < 6; j++) {
if (u.a[p] != v.a[j]) {
sig = 1;
break;
}
p = (p + 5) % 6;
}
if (!sig) break;
}
if (!sig) return true;
return false;
}
inline void hashit(node u) {
int t = Hash(u);
while (hash[t] != -1) {
if (clockwise(u, snow[hash[t]]) || counterClockwise(u, snow[hash[t]])) {
flag = 1;
return;
}
t = (t + 10) % mod;
}
hash[t] = u.tag;
}
void read() {
char c;
n = 0;
while (~scanf("%c", &c) && c != '\n') n = 10 * n + c - '0';
int t, cnt;
for (int i = 0; i < n; i++) {
snow[i].tag = i;
t = cnt = 0;
while (c = getchar()) {
if (c == ' ') {
snow[i].a[cnt++] = t;
t = 0;
continue;
}
else if (c == '\n') {
snow[i].a[cnt++] = t;
break;
}
t = 10 * t + c - '0';
}
// for (int j = 0; j < cnt; j++) printf("%d%c", snow[i].a[j], " \n"[j == cnt - 1]);
}
}
int main() {
memset(hash, -1, sizeof(hash));
read();
for (int i = 0; i < n; i++) if (!flag) {
hashit(snow[i]);
}
if (flag) puts("Twin snowflakes found.");
else puts("No two snowflakes are alike.");
return 0;
}
看了看discuss,archerstarlee总结了大家用的Hash方法,上面的是直接相加模大质数。
然后我试了最后一种,时间降到2700ms。
const int mod = 1e6 + 3;
inline int Hash(int u) {
return ((a[u][0] + a[u][2] + a[u][4]) ^ (a[u][1] + a[u][3] + a[u][5])) % mod;
}
当我用了数的平方和取模时,简直吓死。。
inline int Hash(int u) {
ll t = 0;
for (int i = 0; i < 6; i++)
t += (ll)a[u][i] * a[u][i] % mod; // mod = 1e6 + 3;
return (int)t % mod;
}
“六个数中非零数的积再乘上一个大质数,然后模一个100w上下的数。自己拿随机数据测下来110w左右的效果最好,随机情况下数据量是10w的时候hash值相同的情况只有6k多个,几乎可以忽略。(by killertom)”
这个评测结果也很好,579ms。
总而言之,哈希函数的选取很重要,慢慢攒经验吧。