题意分析:
平面中有n个点,求这些点能组成多少个正方形?
解题思路:
最多1e3个点,四个点枚举肯定超时,必须控制在两个点以内。那么两个点可行吗?下面这幅图可以说明可行:
当一条边确定以后,由等边三角形的特性,旁边的两个点也能枚举出来。
所以有(i是a点,j是b点):
temp.x = p[i].x + (p[i].y - p[j].y);
temp.y = p[i].y + (p[j].x - p[i].x);
和
temp.x = p[j].x + (p[i].y - p[j].y);
temp.y = p[j].y + (p[j].x - p[i].x);
然后用二分搜索查找点是否在图中即可。
由于经过坐标排序后,每个矩形会被枚举两次,最终答案要除以2。
例如上图,当枚举边cd和边bd时会枚举到上图的矩形。
个人感受:
第一想法是枚举两条边= =。发现也是复杂度其高啊。一条边出其它点,这种做法真是对我等数学渣的摧残啊。
具体代码如下:
#include<algorithm> #include<cctype> #include<cmath> #include<cstdio> #include<cstring> #include<iomanip> #include<iostream> #include<map> #include<queue> #include<set> #include<sstream> #include<stack> #include<string> #define lowbit(x) (x & (-x)) #define root 1, n, 1 #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 1 #define ll long long #define pii pair<int, int> #define pr(x) cout << #x << " = " << (x) << '\n'; using namespace std; const int INF = 0x7f7f7f7f; const int MAXN = 1e3 + 111; struct P { int x, y; bool operator < (const P &t)const { if (x == t.x) return y < t.y; return x < t.x; } }p[MAXN], temp; bool binary(int l, int r) { if (l > r) return 0; int m = (l + r) / 2; if (p[m].x == temp.x && p[m].y == temp.y) return 1; else if (temp < p[m]) return binary(l, m - 1); else return binary(m + 1, r); } int main() { #ifdef LOCAL freopen("C:\\Users\\apple\\Desktop\\in.txt", "r", stdin); #endif int n; while (~scanf("%d", &n) && n) { for (int i = 0; i < n; ++i) scanf("%d%d", &p[i].x, &p[i].y); sort(p, p + n); int ans = 0; for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { temp.x = p[i].x + (p[i].y - p[j].y); temp.y = p[i].y + (p[j].x - p[i].x); //cout << 1 << ':' << temp.x << ' ' << temp.y << '\n'; if (!binary(0, n - 1)) continue; temp.x = p[j].x + (p[i].y - p[j].y); temp.y = p[j].y + (p[j].x - p[i].x); //cout << 2 << ':' << temp.x << ' ' << temp.y << '\n'; if (!binary(0, n - 1)) continue; ++ans; } } printf("%d\n", ans/2); } return 0; }