Hash (poj2002-Squares & poj3349-Snowflake Snow Snowflakes)
//突然发现好弱,好多基础的算法竟然都不会,哈希这种经典的算法,我貌似基本没怎么做过相关的题0.0
题意:给n个点,问有多少组四个点能组成正方形。
题解:枚举两个点,通过公式算出另外两个点,然后通过哈希查找另外两个点存不存在。
公式是抄网上的,哈希直接用了vector存的,反正时限3500ms
点的哈希就是(x^2+y^2)%MOD
AC代码:
/************************************** Memory: 924 KB Time: 969 MS Language: G++ Result: Accepted **************************************/ #include <cstdio> #include <cstring> #include <vector> using namespace std; const int MOD = 20007; const int N = 1005; struct Point { int x, y; int key; } p[N]; int cal(int x, int y) { return (x*x+y*y) % MOD; } vector<int> vec[MOD]; void insert(int x) { vec[p[x].key].push_back(x); } bool find(int x, int y) { int k = cal(x, y); for (unsigned i = 0; i < vec[k].size(); ++i) { int v = vec[k][i]; if (x == p[v].x && y == p[v].y) return true; } return false; } int main() { //freopen("in", "r", stdin); int n; while (~scanf("%d", &n) && n) { for (int i = 0; i < MOD; ++i) vec[i].clear(); for (int i = 0; i < n; ++i) { scanf("%d%d", &p[i].x, &p[i].y); p[i].key = cal(p[i].x, p[i].y); insert(i); } int ans = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i == j) continue; int x1 = p[i].x-p[j].y+p[i].y; int y1 = p[i].y+p[j].x-p[i].x; int x2 = p[j].x-p[j].y+p[i].y; int y2 = p[j].y+p[j].x-p[i].x; if (find(x1,y1) && find(x2,y2)) ++ans; } } printf("%d\n", ans/4); } return 0; }
求有没有相同的雪花,每个雪花有12中hash值,分别试一次,插入一个就可以了。时间复杂度O(n*12)。
本来用的上面vector的,然后T了好久T^T
后来改成了类似存图时前向星的方法,3438ms水过去了。
#include <cstdio> #include <cstring> #include <vector> using namespace std; const int MOD = 999979; const int MAXN = 100010; const int N = 6; int snow[MAXN][N]; int head[MOD]; int nt[MAXN]; int cnt; void insert(int a[], int x) { for (int i = 0; i < N; ++i) snow[cnt][i] = a[i]; nt[cnt] = head[x]; head[x] = cnt++; } bool find(int a[], int x) { //printf("%d %d\n", x, head[x]); for (int i = head[x]; i != -1; i = nt[i]) { //printf("i=%d\n", i); break; for (int j = 0; j < N; ++j) { if (a[j] != snow[i][j]) break; if (j == N-1) return true; } } return false; } int main() { //freopen("in", "r", stdin); int n; while (~scanf("%d", &n) && n) { cnt = 0; bool fg = false; memset(head, -1, sizeof head); int a[10], b[10]; for (int i = 0; i < n; ++i) { for (int i = 0; i < N; ++i) scanf("%d", a+i); if (fg) continue; int val = 0; for (int i = 0; i < N; ++i) { val = 0; for (int j = 0; j < N; ++j) { val = (val * 10 + a[(i+j)%N]) % MOD; b[j] = a[(i+j)%N]; } if (find(b, val)) { fg = true; break; } val = 0; for (int j = N-1; j >= 0; --j) { b[N-j-1] = a[(i+j)%N]; val = (val * 10 + a[(i+j)%N]) % MOD; } if (find(b, val)) { fg = true; break; } } if(!fg) insert(b, val); } if (fg) puts("Twin snowflakes found."); else puts("No two snowflakes are alike."); } return 0; }