[POJ2002]Squares(计算几何,二分)

时间:2024-07-01 08:04:07

题目链接:http://poj.org/problem?id=2002

给定一堆点,求这些点里哪些点可以构成正方形,题目给定n<=1000,直接枚举四个点是肯定会超时的,因此要做一些优化。

有公式,已知两个点在正方形对角,分别是(x1,y1)和(x2,y2),那么围成正方形后另外两个点(x3,y3)和(x4,y4)分别为:

x3 = x2 - (x2 - y1)
y3 = x2 + (x2 - x1)
x4 = x1 - (x2 - y1)
y4 = y1 + (x2 - x1)

那么我们需要枚举两个点,最后推算出这两个点和哪两个点可以围成正方形,然后再去查看剩下的点集里是否存在这两个点。我先排序,再做的二分查找,这个题也可以用hash去做,通过hash可以在O(1)的时间内确定是否存在,更加快捷。特别需要注意的是,假如存在一个正方形,那么必然会枚举到这里面的分别两条边。这个时候需要除以2即可。

 #include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath> using namespace std; const int maxn = ;
typedef struct Point {
int x, y;
Point() {}
Point(int xx, int yy) : x(xx), y(yy) {}
}Point;
int n, ans;
Point p[maxn]; bool cmp(Point a, Point b) {
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
} bool bs(int x, int y) {
int ll = , rr = n, mm;
while(ll <= rr) {
mm = (ll + rr) >> ;
if(p[mm].x == x && p[mm].y == y) return ;
else if(cmp(p[mm], Point(x, y))) ll = mm + ;
else rr = mm - ; }
return ;
} int main() {
// freopen("in", "r", stdin);
int x3, y3, x4, y4;
while(~scanf("%d", &n) && n) {
ans = ;
for(int i = ; i < n; i++) {
scanf("%d%d", &p[i].x, &p[i].y);
}
sort(p, p+n, cmp);
for(int i = ; i < n; i++) {
for(int j = i + ; j < n; j++) {
x3 = p[j].x - (p[j].y - p[i].y);
y3 = p[j].y + (p[j].x - p[i].x);
x4 = p[i].x - (p[j].y - p[i].y);
y4 = p[i].y + (p[j].x - p[i].x);
if(bs(x3, y3) && bs(x4, y4)) ans++;
}
}
printf("%d\n", ans / );
}
return ;
}