[最小表示]PKU 3349 Snowflake Snow Snowflakes
最小表示法 + 排序 + 枚举, 整体复杂度:O(n*lgn*6)
这道题普通的枚举就可以做,hash 和枚举差不多,繁琐的地方都在判断是否同构那里,我干脆用最小表示法把原串转换为原串的最小表示和反串的最小表示中的较小者,然后排序,枚举相邻的位置的串是否相等;
最小表示法的一点更正:这篇博文中作者做了一个优化,我以前是参考优化后的做法写的,现在发现评论中有人提到了一个问题(最小位置直接出现在对升序序列后的情况下,这个优化实际上使复杂度变为了O(n^2),已经验证),把 j 减少到 i+1 不合理,所以又回到了原始的做法,具体见代码。
# include <stdio.h> # include <string.h> # include <stdlib.h> # define N 100005 int n; int a[N][6]; /*******************************************/ int mr(int *v, int nn) { int i = 0, j = 1, cnt = 0, t; while (i<nn && j<nn && cnt<nn) { t = v[(i+cnt)%nn] - v[(j+cnt)%nn]; if (!t) ++cnt; else { if (t > 0) i = i+cnt+1; else j = j+cnt+1; if (i == j) ++j; cnt = 0; } } return i<j ? i:j; } /*******************************************/ int acmp(int *s, int *t) { int i; for (i = 0; i < 6; ++i) if (s[i] < t[i]) return -1; else if (s[i] > t[i]) return 1; return 0; } void process(int *t, int k) { int i, u[6], v[6], s, tmp; s = mr(t, 6); for (i = 0; i < 6; ++i) u[i] = t[(s+i)%6]; for (i = 0; i < 3; ++i) { tmp = t[i]; t[i] = t[5-i]; t[5-i] = tmp; } s = mr(t, 6); for (i = 0; i < 6; ++i) v[i] = t[(s+i)%6]; if (acmp(u, v) < 0) memcpy(a[k], u, sizeof(int)*6); else memcpy(a[k], v, sizeof(int)*6); } /*******************************************/ int cmp(const void *xx, const void *yy) { int i, *x = (int*)xx, *y = (int *)yy; for (i = 0; i < 6; ++i) if (*(x+i) < *(y+i)) return -1; else if (*(x+i) > *(y+i)) return 1; return 0; } void solve(void) { int i, j, t[6], found = 0; for (i = 0; i < n; ++i) { for (j = 0; j < 6; ++j) scanf("%d", &t[j]); process(t, i); } qsort(a, n, sizeof(a[0]), cmp); for (i = 1; i < n; ++i) { if (acmp(a[i], a[i-1]) == 0) { found = 1; break; } } puts(found ? "Twin snowflakes found.":"No two snowflakes are alike."); } /*******************************************/ int main() { while (~scanf("%d", &n)) solve(); return 0; }