题目链接:http://poj.org/problem?id=2002
题意:给定n个点,问有多少种方法可以组成正方形。
思路:我们可以根据两个点求出对应正方形[有2个一个在两点左边,一个在两点右边]另外两个点的左边。例如
已知:(x1,y1) (x2,y2)
则x3=x1+(y1-y2) y3= y1-(x1-x2) x4=x2+(y1-y2) y4= y2-(x1-x2)
或x3=x1-(y1-y2) y3= y1+(x1-x2) x4=x2-(y1-y2) y4= y2+(x1-x2)
枚举两个点,进行HASH,然后再枚举两个点然后求另外两个点,再从HASH表找,冲突用拉链法。
这种做法会使同一个正方形按照不同的顺序被枚举了四次,因此最后的结果要除以4.
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<string> #include<vector> #include<cmath> #include<set> using namespace std; typedef long long int LL; typedef unsigned int uint; const int MAXN=1000+5; const int MOD=99991; struct Point{ int x,y; Point(int a=0,int b=0):x(a),y(b){}; }; Point P[MAXN]; vector<Point>Hash[MOD]; void Init(){ for(int i=0;i<MOD;i++){ Hash[i].clear(); } } void InsetHash(Point a){ int Num=(a.x*a.x+a.y*a.y)%MOD; Hash[Num].push_back(a); } bool Search(Point a){ int Num=(a.x*a.x+a.y*a.y)%MOD; for(int i=0;i<Hash[Num].size();i++){ if(a.x==Hash[Num][i].x&&a.y==Hash[Num][i].y){ return true; } } return false; } int main(){ #ifdef kirito freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int n; while(scanf("%d",&n)&&n){ int ans=0; Init(); for(int i=0;i<n;i++){ scanf("%d %d",&P[i].x,&P[i].y); } for(int i=0;i<n;i++){ InsetHash(P[i]); } for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ Point C,D; C.x=P[i].x+(P[i].y-P[j].y); C.y=P[i].y-(P[i].x-P[j].x); D.x=P[j].x+(P[i].y-P[j].y); D.y=P[j].y-(P[i].x-P[j].x); if(Search(C)&&Search(D)){ ans++; } C.x=P[i].x-(P[i].y-P[j].y); C.y=P[i].y+(P[i].x-P[j].x); D.x=P[j].x-(P[i].y-P[j].y); D.y=P[j].y+(P[i].x-P[j].x); if(Search(C)&&Search(D)){ ans++; } } } printf("%d ",ans>>2); } return 0; }