正方形个数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yiyiyizqy/article/details/70258597

题目描述

给定n个点,求可以组成的正方形的个数。(这些正方形可以倾斜)
数据范围:n<=1000,点的坐标<=20000

输入格式 1811.in

有多组测试数据。
对于每一组数据:
第1行为一个整数n。表示点的个数
第2至n+1行,每行两个数Xi,Yi,表示每个点的坐标。
当n=0时,输入结束。

输出格式 1811.out

对于每组数据,输出一个整数。为组成正方形的个数

输入样例 1811.in

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

输出样例 1811.out

1
6
1

    一直觉得哈希是一个很神奇的东西,特别是做了这题以后。

    我们想了想,收到解方程那题的启发,于是决定枚举两个点,因为得出两个点以后,另外与之构成正方形的两个点就能很容易地算出来。

    分类讨论:正正方形,斜正方形。

    正正方形(画得有点丑 嘻嘻):

 (懒得画样例,干脆自己举一个例子)在一个平面直角坐标系中,如果枚举出两个点,一个点A(1,0),B(3,0),如果要和这两个点构成一个正方形,要怎么取。

    很容易知道,这个正方形的边长为2,所以,另外两个点就为(1,2)和(3,2)。但是,可能会想到也可以是(1,-2)啊。那么情况岂不是挺多的。这种正方形就交给下面的两个点(1,-2)和(3,-2)去考虑就好了。


手绘(不错吧)

    这么快就完了吗?想多了。还有另外一种情况,打斜着放,当初LGJ和我们说全都是打正的时候,天真无邪的我们还相信了,然而最后一个样例。。。

    再画一个图:

 

    得出A B以后,C D两个点的横纵坐标就出来了,CD横坐标分别是AB的横坐标减AB纵坐标的差,CD纵坐标是AB的纵坐标加AB横坐标的和。

    至于其他各个边的各种斜的情况,还是暂时不考虑,只考虑枚举到的点i的横纵坐标分别比j小。

 

    一开始我们用一种很暴力很暴力的方法,输入的时候,把有的点v[x][y]记为1。枚举两个点以后,得出另外两个点,如果另外两个点都存在的话,ans就++。 但是题目的数据点的坐标有到20000,,没办法,就开了一个3000的二维数组,撞撞运气。

    不过要注意,有负数,最好位移一下,然后又很随便地位移了1000位。

    一交,竟然有95分(注意满分可是100分,不是200),特别神奇,也不知道是不是smoj的数据(同学出的)太水了。

 

    不过嘛,骗分还是不太道德的。后来,把它换成了线性探测。用这个点的横坐标%prime作为地址,记录x和y,然后找。

    不过超时了一大堆,可能是因为冲突太多。后来在网上查到,解决负数的方法可以用平方,毕竟我们也不知道最大的负坐标是多少(题目没说)。以横纵坐标的平方和作为地址。

    这样做的好处是,减少很多冲突?

#include
#include
#include
#include
using namespace std;
int n,ans,prime=1069;
struct ee
{
	int x,y;
}a[1100];
struct hh
{
	int x1,y1,count;
}hash[1100];
void find(int now,int x1,int y1)
{
	int add=now%prime;
	while((hash[add].x1!=x1||hash[add].y1!=y1)&&hash[add].count!=0)
	{
		add+=(now%101)+1;
		if(add>=prime) add=add%prime;
	}
	hash[add].x1=x1;
	hash[add].y1=y1;
	hash[add].count++;
} 
int cheak(int now,int x1,int y1)
{
	int add=now%prime;
	while((hash[add].x1!=x1||hash[add].y1!=y1)&&hash[add].count!=0)
	{
		add+=(now%101)+1;
		if(add>=prime) add=add%prime;
	}
	return hash[add].count;
}
int main()
{
	freopen("1811.in","r",stdin);
	freopen("1811.out","w",stdout);
	while(1)
	{
		ans=0;
		memset(hash,0,sizeof(hash));
		cin>>n;
		if(n==0) break;
		for(int i=1;i<=n;i++) 
		{
			cin>>a[i].x>>a[i].y;
			find(a[i].x*a[i].x+a[i].y*a[i].y,a[i].x,a[i].y);
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i==j) continue;
				if(a[i].y==a[j].y&&a[i].x

           代码写得不太好,有些地方太长了,容易出错,不妨写一个函数算每个数的平方?

    PS:第一次在这里正式上传总结,多多指教

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页