POJ 2002 Squares 解題報告(哈希 開放尋址 & 鏈式)

    經典好題。函數

    題意是要咱們找出全部的正方形。1000點,只有枚舉咯。測試

    如圖,若是咱們知道了正方形A,B的座標,即可以推測出C,D兩點的座標。反之,遍歷全部點做爲A,B點,看C,D點是否存在。存在的話正方形數+1。優化

    假設A點座標爲(x1,y1),B點座標爲(x2,y2),則根據三角形全等,易知spa

    C點座標:( x1+(y2-y1),y1-(x2-x1) )code

    D點座標:( x2+(y2-y1),y2-(x2-x1) )htm

    固然,若是咱們遍歷任意兩個點,一個正方形將會被計數四次(四條邊)。咱們能夠只判斷斜率>=0的邊,這條邊在正方形的上方(如圖AB邊),這樣不用重複驗證四次了。blog

 

    過程搞清楚了,下面要解決的就是如何判斷C,D點是否存在了。內存

    最簡單的辦法,直接使用set。咱們把出現的點加到set裏,判斷時用find函數便可。固然,時效比較差。筆者測試是1000MS+。string

    然後,咱們也能夠使用二分查找。hash

    固然,最快仍是hash了。hash分爲兩種,開放尋址和鏈式,來解決衝突。在網上搜了不少解題報告,發現你們不少把鏈式叫作開放尋址……百度百科上有說明,你們能夠看一下:http://baike.baidu.com/view/3140124.htm

    下面,貼代碼:

    開放尋址,POJ測試最快是219MS,125MS級別的代碼不知是如何實現的==

#include <cstdio>
#include <cstring>

int prime[]={2,3,5,7,11,13,17,19};

int x[1001],y[1001];
int savex[262144],savey[262144];
bool hash[262144];

inline int calHash(int x,int y)
{
    return ((x<<7)^y)&262143;
}

void insert(int x,int y)
{
    int h=calHash(x,y);
    int add=prime[(x^y)&7];
    while(hash[h] && (savex[h]!=x || savey[h]!=y))
    {
        h+=add;
        h&=262143;
    }
    hash[h]=true;
    savex[h]=x;
    savey[h]=y;
}

bool find(int x,int y)
{
    int h=calHash(x,y);
    int add=prime[(x^y)&7];
    while(hash[h] && (savex[h]!=x || savey[h]!=y))
    {
        h+=add;
        h&=262143;
    }
    if(hash[h] && savex[h]==x && savey[h]==y)
        return true;
    return false;
}

bool calK(int a,int b)
{
    if(x[a]==x[b])
        return false;
    if(y[a]==y[b])
        return true;
    if(((x[a]-x[b])&(1<<31))==((y[a]-y[b])&(1<<31)))
        return true;
    return false;
}

inline int Abs(int n)
{
    return n<0?-n:n;
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n;
    while(~scanf("%d",&n) && n)
    {
        memset(hash,0,sizeof(hash));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",x+i,y+i);
            insert(x[i],y[i]);
        }

        int count=0;
        for(int i=0;i<n;i++)
            for(int k=i+1;k<n;k++)
        {
            if(calK(i,k))
            {
                int _y=Abs(y[i]-y[k]);
                int _x=Abs(x[i]-x[k]);
                if(find(x[i]+_y,y[i]-_x) &&
                   find(x[k]+_y,y[k]-_x))
                    count++;
            }
        }
        printf("%d\n",count);
    }
}

    鏈式,即發現衝突就在當前位置加一個槽。POJ上最快319MS。固然,每次新建的槽並無delete,會形成內存泄露,現實中仍是別這麼幹,或者及時delete吧。

#include <cstdio>
#include <cstring>

struct Point
{
    int x,y;
    bool operator<(const Point& cmp) const
    {
        return x==cmp.x?y<cmp.y:x<cmp.x;
    }
} point[1010],p,q;

struct Hash
{
    int x,y;
    Hash*  next;
    Hash()
    {
        next=0;
    }
} hash[131072];

inline int calHash(int x,int y)
{
    return ((x<<9)^y)&131071;
}

void insert(int x,int y)
{
    int h=calHash(x,y);
    Hash* p=&hash[h];
    while(p->next)
        p=p->next;
    p->x=x;
    p->y=y;
    p->next=new Hash();
}

bool find(int x,int y)
{
    int h=calHash(x,y);
    Hash* p=&hash[h];
    while(p->next)
    {
        if(p->x==x && p->y==y)
            return true;
        p=p->next;
    }
    return false;
}

bool calK(Point& a,Point& b)
{
    if(a.x==b.x)
        return false;
    if(a.y==b.y)
        return true;
    if(((a.x-b.x)&(1<<31))==((a.y-b.y)&(1<<31)))
        return true;
    return false;
}

inline int Abs(int n)
{
    return n<0?-n:n;
}

int main()
{
//  freopen("in.txt","r",stdin);
    int n;
    while(~scanf("%d",&n) && n)
    {
        memset(hash,0,sizeof(hash));
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&point[i].x,&point[i].y);
            insert(point[i].x,point[i].y);
        }

        int count=0;
        for(int i=0;i<n;i++)
            for(int k=i+1;k<n;k++)
        {
            if(calK(point[i],point[k]))
            {
                int _y=Abs(point[i].y-point[k].y);
                int _x=Abs(point[i].x-point[k].x);
                if(find(point[i].x+_y,point[i].y-_x) &&
                   find(point[k].x+_y,point[k].y-_x))
                    count++;
            }
        }
        printf("%d\n",count);
    }
}

    最簡單的辦法,set……1360MS

#include <cstdio>
#include <cstring>
#include <set>
using namespace std;

struct Point
{
    int x,y;
    bool operator<(const Point& cmp) const
    {
        return x==cmp.x?y<cmp.y:x<cmp.x;
    }
} point[1010],p,q;

set<Point> ss;

bool calK(Point& a,Point& b)
{
    if(a.x==b.x)
        return false;
    if(a.y==b.y)
        return true;
    if(((a.x-b.x)&(1<<31))==((a.y-b.y)&(1<<31)))
        return true;
    return false;
}

inline int Abs(int n)
{
    return n<0?-n:n;
}

int main()
{
//    freopen("in.txt","r",stdin);
    int n;
    while(~scanf("%d",&n) && n)
    {
        ss.clear();
        for(int i=0;i<n;i++)
        {
            scanf("%d%d",&point[i].x,&point[i].y);
            ss.insert(point[i]);
        }

        int count=0;
        for(int i=0;i<n;i++)
            for(int k=i+1;k<n;k++)
        {
            if(calK(point[i],point[k]))
            {
                int _y=Abs(point[i].y-point[k].y);
                int _x=Abs(point[i].x-point[k].x);
                p.x=point[i].x+_y;
                p.y=point[i].y-_x;
                if(ss.find(p)==ss.end())
                    continue;

                p.x=point[k].x+_y;
                p.y=point[k].y-_x;
                if(ss.find(p)!=ss.end())
                    count++;
            }
        }
        printf("%d\n",count);
    }
}

    三個版本是慢慢優化出來的,哈希函數也有區別。

相關文章
相關標籤/搜索