题目描述
给定 n 个点,求可以组成的正方形的个数。(这些正方形可以倾斜)
数据范围:n≤1000 ,点的坐标 ≤20000
输入格式 1811.in
有多组测试数据。
对于每一组数据:
第 1 行为一个整数 n 。表示点的个数
第 2 至n+1 行,每行两个数 Xi,Yi ,表示每个点的坐标。
当 n=0 时,输入结束。
输出格式 1811.out
对于每组数据,输出一个整数。为组成正方形的个数
输入样例 1811.in
4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0
输出样例 1811.out
1
6
1
这道题目的题意比较显然,就是要找四个点组成正方形,但是这些正方形的边不一定平行于 x 轴和 y 轴。
可以看到,
既然是要枚举两个点,那么必然要通过一些判断方法得到另外两个点。于是不妨从正方形的性质入手,最显然的一条就是两组对边分别平行且相等,四个角都为 90 度。
如图:
我们现在已经枚举了组成正方形一条边的点
A(x1,y1)
和点
B(x2,y2)
,想要求出能够与它们组成正方形的
C
点和
作点
E(x2,y1)
。作点
F
使
∴AE=x2−x1,BE=y2−y1
∵□ABCD
为正方形
∴AB=BC,∠ABC=90°
∴∠1+∠2=90°
又
∵在△ABE中,∠2+∠3=90°
∴∠1=∠3
∵
在
△ABE
和
△BCF
中,
∠E=∠F=90°,∠1=∠3,AB=BC
∵△ABE≅△BCF
∴AE=BF,BE=CF
∴C(x2−(y2−y1),y2+(x2−x1))
于是这样我们就求得了点
C
的坐标,同理可以得到点
总的做法:将每个点 hash 保存。之后再枚举两个点(注意不是嵌套的四重循环),求得能与它们组成正方形的两个点坐标,如果两个点都存在,那么可以组成一种正方形。
时间复杂度为
O(n2)
。
但是要注意,这样计数,每个正方形会被计算四次(想一想,为什么),因此最终的答案要除以 4。
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1e3 + 10;
const int prime = 30001;
struct Data { int x, y; bool bo; };
int n;
int x[maxn], y[maxn];
Data hash[prime];
void insert(int xx, int yy) {
int h = (xx * xx + yy * yy) % prime;
int p = h;
while ((hash[p].x != xx || hash[p].y != yy) && hash[p].bo) {
p += h % 107 + 1;
if (p >= prime) p -= prime;
}
hash[p].x = xx; hash[p].y = yy;
hash[p].bo = true;
}
bool find(int xx, int yy) {
int h = (xx * xx + yy * yy) % prime;
int p = h;
while ((hash[p].x != xx || hash[p].y != yy) && hash[p].bo) {
p += h % 107 + 1;
if (p >= prime) p -= prime;
}
return hash[p].bo;
}
int main(void) {
freopen("1811.in", "r", stdin);
freopen("1811.out", "w", stdout);
while (~scanf("%d", &n)) {
if (!n) break;
memset(hash, 0, sizeof hash);
for (int i = 0; i < n; i++) {
scanf("%d%d", &x[i], &y[i]);
insert(x[i], y[i]);
}
int ans = 0;
for (int i = 0; i + 1 < n; i++)
for (int j = i + 1; j < n; j++) {
int xc = x[i] - x[j], yc = y[i] - y[j];
if (find(x[i] - yc, y[i] + xc) && find(x[j] - yc, y[j] + xc)) ans++;
if (find(x[i] + yc, y[i] - xc) && find(x[j] + yc, y[j] - xc)) ans++;
}
printf("%d\n", ans >> 2);
}
return 0;
}