题目:给出1000个点,找其中可以构成正方形的个数
基本想法:枚举边,同时满足长度相等,中心相等,方向垂直即可。
方案一:处理出所有的边,log地查找符合要求的边。复杂度(ElogE),E<5*1e5,T
方案二:枚举对角顶点,每次计算出剩下两个顶点的位置,位置都存在点,则满足条件。复杂度(Elogn),E<5*1e5,n<1e3,T。
方案二T了就很懵逼,5*1e6都能跪??
然后发现我在计算的时候用例atan和sin, cos,当时为了解决这个精度问题还要重写比较函数。
把计算方法改成相似计算就行了。
#include<iostream>
#include<map>
#include<cmath>
#include<cstdio>
using namespace std;
const double INF=1e18+7;
struct Key{
double x,y;
Key(){}
Key(double a,double b){
x=a;y=b;
}
bool operator <(Key a)const{
if(abs(x-a.x)>1e-6) return x<a.x;
if(abs(y-a.y)>1e-6) return y<a.y;
return false;
}
};
struct Point{
double x,y;
Point(){}
Point(double x,double y){
this->x=x;
this->y=y;
}
Point operator +(Point a) const{
return Point(x+a.x,y+a.y);
}
Point operator -(Point a) const{
return Point(x-a.x,y-a.y);
}
Point operator *(double k) const{
return Point(x*k,y*k);
}
Point operator /(double k) const{
return Point(x/k,y/k);
}
}p[1010];
double dis(int i,int j){
return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
map<Key, int> mmm;
for(int i=0;i<n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);
mmm[Key(p[i].x,p[i].y)]++;
}
int cnt=0;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
Point a,b;
Point mid((p[i].x+p[j].x)/2,(p[i].y+p[j].y)/2);
double dist=dis(i,j);
if(p[i].x==p[j].x){
a=Point(mid.x+dist/2.0,mid.y);
b=Point(mid.x-dist/2.0,mid.y);
}
else if(p[i].y==p[j].y){
a=Point(mid.x,mid.y+dist/2.0);
b=Point(mid.x,mid.y-dist/2.0);
}
else{
double changex=abs(p[i].x-mid.x);
double changey=abs(p[i].y-mid.y);
double k=(p[i].y-p[j].y)/(p[i].x-p[j].x);
if(k>0){
a=Point(mid.x+changey,mid.y-changex);
b=Point(mid.x-changey,mid.y+changex);
}
else{
a=Point(mid.x+changey,mid.y+changex);
b=Point(mid.x-changey,mid.y-changex);
}
}
if(mmm[Key(a.x,a.y)]&&mmm[Key(b.x,b.y)]) cnt++;
}
}
cout<<cnt/2<<endl;
}
}