POJ2002---正方形

这篇博客讨论了一种算法问题,涉及在一组给定的二维坐标点中找出能构成正方形的组合。通过枚举两个点并计算其他两个可能的正方形顶点,利用哈希表存储和查找,来提高效率。文章提供了详细的思路分析和C++代码实现,解释了如何避免超时并正确计算正方形的数量。
摘要由CSDN通过智能技术生成

题目描述

正方形是边长相等且相邻边形成90度角的4边多边形。它也是一个多边形,围绕其中心旋转 90 度会得到相同的多边形。然而,它不是唯一具有后一特性的多边形,因为正八边形也具有此特性。

所以我们都知道正方形是什么样子的,但是我们能找到所有可能由夜空中的一组星星组成的正方形吗?为了使问题更容易,我们假设夜空是一个二维平面,每颗星星都由它的 x 和 y 坐标指定。

输入

输入由许多测试用例组成。每个测试用例以整数 n (1 <= n <= 1000) 开始,表示要跟踪的点数。接下来的 n 行中的每一行都指定了每个点的 x 和 y 坐标(两个整数)。您可以假设点是不同的,并且坐标的大小小于 20000。当 n = 0 时,输入终止。

输出

对于每个测试用例,在一行上打印一个人可以从给定的星星形成的正方形数。

Sample Input

4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0

Sample Output

1
6
1

思路分析

题目分析:直接将四个点枚举会超时,所以任意枚举两个点,将任意两个点算出来后判断是否在自己创建的hash表中.可以按照什么规则呢?如下图所示,我们把两个点当成相邻边的点,我们可以算出其他两个点的坐标.
在这里插入图片描述
假设x1,x2,x3,x4的输入顺序是x1,x2,x3,x4则在进行枚举时(先以右上正方形为例)对于一个正方形会被ans++四次.

i-->x1;j-->x2;
i-->x1;j-->x4;
i-->x2;j-->x3;
i-->x3;j-->x4

当枚举到这四种情况时,都可以在hashTab中找到该正方形的其他两点,并且这四种情况对应的是同一个正方形.
同理左下正方形也是这个规律.
所以最终结果ans要 / 4;

参考代码

//POJ2002
#include<iostream>
using namespace std;
const int N=1010;
const int H=10007;
int ptx[N],pty[N];

struct Node{
	int x;
	int y;
	int next;
}; 

Node node[N];
int cur;//控制当前静态链表的下标的 
int n;
long ans;//统计数目
int hashTab[H];

void initHash() //这里不能使用memset因为这个仅对字符数组有效 
{
	for(int i = 0;i<H;i++){
		hashTab[i] = -1;
	}
	cur = 0;
	ans = 0;
 } 

void insertHash(int x,int y){
	int h = (x*x+y*y)%H; //Hash函数计算地址
	node[cur].x = x;
	node[cur].y = y;
	node[cur].next  = hashTab[h];//采用前插法 
	hashTab[h] = cur;
	cur++;
} 

int searchHash(int x,int y)
{
	int h = (x*x+y*y) % H;
	int next;
	next = hashTab[h];
	while(next!=-1){
		if(x==node[next].x&&y==node[next].y){
			return 1;
		} 
		next = node[next].next;
	}
	return 0;
 } 
 
 int main()
 {
 	while(cin>>n&&n){
 		initHash();
 		for(int i = 0;i<n;i++)
 		{
 			scanf("%d%d",&ptx[i],&pty[i]);
 			insertHash(ptx[i],pty[i]);
		}
		for(int i = 0; i< n;i++){
			for(int j = i+1;j<n;j++){
				int x3 = ptx[j]+(pty[i]-pty[j]);
				int y3 = pty[j]+(ptx[j]-ptx[i]);
				int x4 = ptx[i]+(pty[i]-pty[j]);
				int y4 = pty[i]+(ptx[j]-ptx[i]);
				if(searchHash(x3,y3)&&searchHash(x4,y4)){
					ans++;
				}
			}
		}
		for(int i = 0; i< n;i++){
			for(int j = i+1;j<n;j++){
				int x3 = ptx[j]-(pty[i]-pty[j]);
				int y3 = pty[j]-(ptx[j]-ptx[i]);
				int x4 = ptx[i]-(pty[i]-pty[j]);
				int y4 = pty[i]-(ptx[j]-ptx[i]);
				if(searchHash(x3,y3)&&searchHash(x4,y4)){
					ans++;
				}
			}
		}
		ans>>=2;
		printf("%ld\n",ans);
	 }
 	return 0;
 }

注意:本题使用线性探测法会出现多个数据堆积,然后运行超时.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的大李子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值