POJ-2002 Squares Hash表+正方形顶点计算
该题的思路就是枚举所有的点,当然这么枚举要做到不能够重复和遗漏,所以我们约定值枚举对角线的两个点,最后将最终的结果除以2来计算。
由于每次通过枚举对角线的两个点,我们还要计算出另外两个顶点的坐标,所以这里用了一个很牛的公式,直接作加减法就能够出来了,判定下是否为整数。理论上我们马上要到点集中去寻找有没有这两个点,显然这种做法的效率很低,所以这里要用hash表,将顶点的信息的查询优化到接近O(1)。
这里把正方形计算另外两个顶点的公式记录如下(已知x1, x2, y1, y2, 求x3, y3, x4, y4):
x1 + x2 = x3 + x4;
y2 - y1 = x4 - x3;
y1 + y2 = y3 + y4;
x2 - x1 = y3 - y4;
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #define MAXN 30001 #define MOD 30001 using namespace std; int N, head[MAXN], idx; struct Point { int x, y; }p[10005]; struct Node { int x, y, next; }e[10005]; void Hash(int x, int y) { int key = abs(x * y) % MOD; ++idx; e[idx].x = x, e[idx].y = y; e[idx].next = head[key]; head[key] = idx; } bool find(int x, int y) { int key = abs(x * y) % MOD, ans = 0; for (int i = head[key]; i != -1; i = e[i].next) { if (e[i].x == x && e[i].y == y) { return true; } } return false; } int main() { int ans; while (scanf("%d", &N), N) { memset(head, 0xff, sizeof (head)); idx = -1; ans = 0; for (int i = 0; i < N; ++i) { scanf("%d %d", &p[i].x, &p[i].y); Hash(p[i].x, p[i].y); } double x1, y1, x2, y2; for (int i = 0; i < N; ++i) { for (int j = i+1; j < N; ++j) { x1 = ( (p[i].x + p[j].x) + (p[j].y - p[i].y) ) / 2.; x2 = ( (p[i].x + p[j].x) - (p[j].y - p[i].y) ) / 2.; y1 = ( (p[j].y + p[i].y) - (p[j].x - p[i].x) ) / 2.; y2 = ( (p[j].y + p[i].y) + (p[j].x - p[i].x) ) / 2.; if (x1 == floor(x1) && x2 == floor(x2) && y1 == floor(y1) && y2 == floor(y2)) { if (find(x1, y1) && find(x2, y2)) { ++ans; } } } } printf("%d\n", ans >> 1); } return 0; }