题面
【题目描述】
给出平面上一些点的坐标,统计由这些点可以组成多少个正方形。注意:正方形的边不一定平行于坐标轴。
【输入】
输入包括多组测试数据。每组的第一行是一个整数n (1 <= n <= 1000),表示平面上点的数目,接下来n行,每行包括两个整数,分别给出一个点在平面上的x坐标和y坐标。输入保证:平面上点的位置是两两不同的,而且坐标的绝对值都不大于50000。最后一组输入数据中n = 0,这组数据表示输入的结束,不用进行处理。
【输出】
对每组输入数据,输出一行,表示这些点能够组成的正方形的数目。
【样例输入】
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
【样例输出】
1
6
1
算法分析
哈希表
如果枚举四个点,时间复杂度为
O
(
N
4
)
O(N^4)
O(N4),严重超时。
对于一个正方形,有一个特性,知道任意两点,就可以知道其他两点。因此可以枚举其中两个点,计算出另外两个点,判断另外两个点是否存在。
判断某个点是否存在,使用哈希表,时间复杂度
O
(
N
2
)
O(N^2)
O(N2)。
参考程序
#include<bits/stdc++.h>
#define N 1000100
#define M 999991
#define ll long long
using namespace std;
int h[N],nex[N], xx[N],yy[N],tot;
ll x[1010],y[1010];
void H(ll i,ll j)
{
ll s=i*i+j*j;//哈希值
s=s%M;
nex[++tot]=h[s]; //链表解决冲突
h[s]=tot; //记录哈希值为s的横坐标,纵坐标
xx[tot]=i;
yy[tot]=j;
}
int check(ll i,ll j)
{
ll s=i*i+j*j;
s=s%M;
//cout<<i<<" "<<j<<" "<<"="<<s<<endl;
for(int k=h[s];k!=-1;k=nex[k])
{
if(xx[k]==i&&yy[k]==j) return 1;
}
return 0;
}
int main()
{
while(1)
{
memset(h,-1,sizeof(h));
int n,ans=0;
scanf("%d",&n);
if(n==0) break;
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&x[i],&y[i]);
H(x[i],y[i]); //每个点使用hash表标记是否出现
}
for(int i=1;i<=n;i++)//根据两个点计算另外两个点
{
for(int j=1;j<=n;j++)
{
if(i==j) continue;
ll a,b,c,d;
a=x[j]-(y[j]-y[i]);
b=y[j]+x[j]-x[i];
c=x[i]-(y[j]-y[i]);
d=y[i]+x[j]-x[i];
if(check(a,b)&&check(c,d)) ans++;
}
}
printf("%d\n",ans/4);
}
return 0;
}