题目传送门

【题意】给出n个二维平面上的坐标,求出这n个坐标最多能够构成多少个正方形。

【解题思路】自己完全不会做,只好看网上题解了,现在把Hash和二分的解法展示如下,首先说一说解题的思路,

通过n最大为1000可以推测,应该是n^2左右的效率,所以我们先枚举两个点,然后通过这两个点再求出另外两个点的坐标,在输入的集合中查找是否存在这两个点,如果存在的话就可以构成一个正方形。

但是枚举也有一定的方法,我们不能随便枚举,因为有很多种形状的正方形,我们也不知道这两个点是正方形的哪两个点。首先,我们要先将所有的点按照x,y的大小排好序,然后遍历的时候取a[i]和a[j]两个点,且i<j,即a[i].x<a[j].x || a[i].x==a[j].x&&a[i].y<a[j].y。这样子我们就可以自定义是哪两个点:


比如这么一个正方形,我们已知1,2两个点的坐标为(a1,a2),(b1,b2),那么我们怎么求得3,4两个点的坐标那?其实正方形有它的特殊性。


我们可以看出,上下做的两个三角形是全等的,所以说对于点3,点3的坐标为(a1+(b2-a2),a2-(b1-a1)),同理,点4的坐标为(b1+(b2-a2),b2-(b1-a1))。知道了这两个点,就可以去找了。

但是如果会问,那么如果遍历到的是1,3怎么办?其实不用管,因为这个是按从小到大来遍历的,那么1,2两个点肯定会被遍历到,就不用管1,3了。还有一点,如果我们遍历到的是2,4两个顶点,那么计算1,3两个定点的时候,计算公式是和知道1,3一样的。所以,对于每个四边形,我们都遍历了两遍,最后除以2即可。

对于查找的算法,我们可以用哈希或者二分即可。

【AC代码,Hash版本】

<span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px; "><strong>Memory:</strong></span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;"> 4088K</span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px; "><strong>Time:</strong></span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;"> 438MS</span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px; "><strong>Language:</strong></span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;"> C++</span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px; "><strong>Result:</strong></span><span style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;"> </span><span style="font-family: Arial; font-size: 14px; line-height: 26px; color: blue;">Accepted</span>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int nn = 1010;

struct node{
   int x,y;
   friend bool operator<(const node &aa,const node &bb)
   {
       if(aa.x==bb.x)
          return aa.y<bb.y;
       return aa.x<bb.x;
   }
}a[nn];
int n;
int Hash[1000010],Next[1010];
bool check(int x,int y)
{
    int key = abs(x+y);
    int id = Hash[key];
    while(id!=-1)
    {
        if(a[id].x==x&&a[id].y==y)
        {
            return true;
        }
        id = Next[id];
    }
    return false;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        memset(Hash,-1,sizeof(Hash));
        memset(Next,-1,sizeof(Next));
        for(int i=0; i<n; i++) scanf("%d%d",&a[i].x,&a[i].y);
        sort(a,a+n);
        for(int i=0; i<n; i++)//hash.
        {
            int tmp = abs(a[i].x+a[i].y);
            Next[i] = Hash[tmp]; //通过Next这个链式指针,为了check.
            Hash[tmp] = i;
        }
        int ans = 0;
        for(int i=0; i<n; i++)
        {
            for(int j=i+1; j<n; j++)
            {
                int px = a[j].x-a[i].x;
                int py = a[j].y-a[i].y;
                int xx = a[i].x+py;
                int yy = a[i].y-px;
                if(!check(xx,yy))continue; //3 point.
                xx = a[j].x+py;
                yy = a[j].y-px;
                if(!check(xx,yy))continue;
                ans++;
            }
        }
        printf("%d\n",ans/2);//over count.
    }
    return 0;
}
【AC代码,二分版本】
Memory: 172K Time: 1313MS Language: C++ Result:  Accepted

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int nn = 1010;
struct node{
   int x,y;
   friend bool operator<(const node &aa,const node &bb)
   {
       if(aa.x==bb.x)
          return aa.y<bb.y;
       return aa.x<bb.x;
   }
}a[nn];
int n;
bool Cmp(int x,int y,node &S)
{
    if(x<S.x)return true;
    if(x==S.x&&y<S.y)return true;
    return false;
}
bool check(int x,int y)
{
    int l=0,r=n;
    int m;
    while(l<=r)
    {
        m = (l+r)>>1;
        if(a[m].x==x&&a[m].y==y)
            return true;
        if(Cmp(x,y,a[m]))
            r = m-1;
        else
            l = m+1;
    }
    return false;
}
int main()
{
    while(~scanf("%d",&n)&&n)
    {
        for(int i=0; i<n; i++) scanf("%d%d",&a[i].x,&a[i].y);
        sort(a,a+n);
        int ans = 0;
        for(int i=0; i<n; i++)
        {
            for(int j=i+1; j<n; j++)
            {
                int px = a[j].x-a[i].x;
                int py = a[j].y-a[i].y;
                int xx = a[i].x+py;
                int yy = a[i].y-px;
                if(!check(xx,yy))continue;
                xx = a[j].x+py;
                yy = a[j].y-px;
                if(!check(xx,yy))continue;
                ans++;
            }
        }
        printf("%d\n",ans/2);
    }
    return 0;
}
【总结】从HASH和二分的时间和空间消耗上来看,Hash比二分更耗内存,但是耗时却少得多。二分虽然内存小,但是耗时较多。因此,我们在选择二分或者hash都能解决的问题上时,我们应当权衡好这两方面的东西。最近正在努力学习hash的东西,偏向于hash一点,用他们常说的就是(内存又不要钱-><-)。