您的位置:首页 > 其它

POJ 2002 Squares 解题报告(哈希 开放寻址 & 链式)

2013-08-01 01:21 513 查看
经典好题。

题意是要我们找出所有的正方形。1000点,只有枚举咯。

如图,如果我们知道了正方形A,B的坐标,便可以推测出C,D两点的坐标。反之,遍历所有点作为A,B点,看C,D点是否存在。存在的话正方形数+1。



假设A点坐标为(x1,y1),B点坐标为(x2,y2),则根据三角形全等,易知

C点坐标:( x1+(y2-y1),y1-(x2-x1) )

D点坐标:( x2+(y2-y1),y2-(x2-x1) )

当然,如果我们遍历任意两个点,一个正方形将会被计数四次(四条边)。我们可以只判断斜率>=0的边,这条边在正方形的上方(如图AB边),这样不用重复验证四次了。

过程搞清楚了,下面要解决的就是如何判断C,D点是否存在了。

最简单的办法,直接使用set。我们把出现的点加到set里,判断时用find函数即可。当然,时效比较差。笔者测试是1000MS+。

而后,我们也可以使用二分查找。

当然,最快还是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);
}
}


三个版本是慢慢优化出来的,哈希函数也有区别。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: