题目链接: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即可。
1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <fstream> 8 #include <cassert> 9 #include <cstdio> 10 #include <bitset> 11 #include <vector> 12 #include <deque> 13 #include <queue> 14 #include <stack> 15 #include <ctime> 16 #include <set> 17 #include <map> 18 #include <cmath> 19 20 using namespace std; 21 22 const int maxn = 1010; 23 typedef struct Point { 24 int x, y; 25 Point() {} 26 Point(int xx, int yy) : x(xx), y(yy) {} 27 }Point; 28 int n, ans; 29 Point p[maxn]; 30 31 bool cmp(Point a, Point b) { 32 if(a.x == b.x) return a.y < b.y; 33 return a.x < b.x; 34 } 35 36 bool bs(int x, int y) { 37 int ll = 0, rr = n, mm; 38 while(ll <= rr) { 39 mm = (ll + rr) >> 1; 40 if(p[mm].x == x && p[mm].y == y) return 1; 41 else if(cmp(p[mm], Point(x, y))) ll = mm + 1; 42 else rr = mm - 1; 43 44 } 45 return 0; 46 } 47 48 int main() { 49 // freopen("in", "r", stdin); 50 int x3, y3, x4, y4; 51 while(~scanf("%d", &n) && n) { 52 ans = 0; 53 for(int i = 0; i < n; i++) { 54 scanf("%d%d", &p[i].x, &p[i].y); 55 } 56 sort(p, p+n, cmp); 57 for(int i = 0; i < n; i++) { 58 for(int j = i + 1; j < n; j++) { 59 x3 = p[j].x - (p[j].y - p[i].y); 60 y3 = p[j].y + (p[j].x - p[i].x); 61 x4 = p[i].x - (p[j].y - p[i].y); 62 y4 = p[i].y + (p[j].x - p[i].x); 63 if(bs(x3, y3) && bs(x4, y4)) ans++; 64 } 65 } 66 printf("%d\n", ans / 2); 67 } 68 return 0; 69 }
时间: 2024-11-18 04:57:40