poj2002 Squares

【简单实现版】【无手写哈希】Poj 2002正方形个数 Enjoy. 描述 给定直角坐标系中的若干整点寻找可以由这些组成正方形统计它们的个数。 输入 包括多组数据,每组数据的第一行是整点个数n(1<=n<=1000),其后n行每行由两个整数组成,表示一个的x、y坐标。输入保证一组数据中不会出现相同的,且坐标的绝对值小于等于20000。输入以一组n=0的数据结尾。 输出 对于每组输入数据,输出一个数,表示这组数据中的可以组成正方形的数量。 样例输入 4 1 0 0 1 1 1 0 0 9 0 0 1 0 2 0 0 2 1 2 2 2 0 1 阅读详情

这是题目:

2:正方形
查看 提交 统计 提问
总时间限制: 3500ms 内存限制: 65536kB
描述
给定直角坐标系中的若干整点,请寻找可以由这些点组成的正方形,并统计它们的个数。
输入
包括多组数据,每组数据的第一行是整点的个数n(1<=n<=1000),其后n行每行由两个整数组成,表示一个点的x、y坐标。输入保证一组数据中不会出现相同的点,且坐标的绝对值小于等于20000(此处翻译有误,应为:点到原点的距离小于等于20000)。输入以一组n=0的数据结尾。
输出
对于每组输入数据,输出一个数,表示这组数据中的点可以组成的正方形的数量。
样例输入
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
样例输出
1
6
1


====================================================================================

  1. 解题思路:枚举点集中的任意两点,假设它们在正方形的一条边上,通过几何关系计算另外两个点的坐标,查找这两个点是否都在点集中,若是,则计数+1,最后得到的计数值除以4(正方形的4条边都会贡献计数)就是正方形的个数。
  2. 时间复杂度:枚举两点的复杂度为O(n^2)查找,采用hash table(此题我采用链地址法解决冲突),时间复杂度近似认为O(1),因此总的时间复杂度为O(n^2)。对于n<=1000的数据规模可以接受。
  3. 如何计算另外两点的坐标?请看下图。
  4. 最后,也是常常被oj忽略的一点:内存回收,具体而言是链地址法中链表结点的回收。从尾结点向首结点回收,用指针栈保存沿途结点的地址。

====================================================================================

代码清单:
//hash table
//采用的散列函数是key=(x^2+y^2)%prime。选择一个prime number尽可能减少冲突。
//基本思路是,点集中任取两个点,假设它们在正方形上,算出另外两个点的坐标,查找这另外两个点是否都在点集中。
//取两个点的复杂度为O(n^2);查找由于使用了hash,复杂度近似认为O(1);因此总的时间复杂度为O(n^2)。对于n<=1000的数据规模可以接受。
//有两点需要注意:1.算出另外两点的坐标,用直观的坐标运算即可。2.每一个正方形有四条边,遍历这四条边的时候各增加计数1次,所以最后的“正方形个数”要除以4才是实际的个数。
#include <cstdio>
#include <stack>
using namespace std;

#define MAXP 1005
#define PRIME 21911 //随便选的一个质数。
#define OUTOFRANGE 999999

typedef struct _point
{
	int x;
	int y;
} point;

typedef struct _hashtab
{
	int x;
	int y;
	struct _hashtab *next;
} hashtab;

//点的个数最多是1000个
point p[MAXP];
//散列长度。根据散列函数和选定的prime,散列长度,即key值的可能性有prime种:0~prime-1。
hashtab ht[PRIME];

void InitHashTab()
{
	for (int i=0; i<PRIME; ++i)
	{
		ht[i].x=OUTOFRANGE;
		ht[i].y=OUTOFRANGE;	
		//没有这两句x和y的初始化答案是wrong answer!为何?
		//当然!下一组数据搜点时,可能会与上一组已有的点重合,所以必须初始化。那么应该初始化为多少呢?
		//由题意,点的域是以原点为圆心、以20,000为半径的圆,包括边。所以选一个大于20,000的数字即可。
		ht[i].next=NULL;
	}
}

void BuildPointAndHashTab(int n)
{
	int x, y;
	int key;
	for (int i=0; i<n; ++i)
	{
		scanf("%d%d", &x, &y);
		p[i].x=x;
		p[i].y=y;

		key=(x*x+y*y)%PRIME;
		//用链地址法解决冲突
		hashtab *pt=&(ht[key]);
		while (pt->next != NULL)	pt=pt->next;
		//当前位置的pt->next==NULL,在当前位置插入数据
		pt->x=x;
		pt->y=y;
		//插入数据后它的next不再可以为NULL,要为这个next分配空间
		pt->next = new hashtab;
		//注意把新分配的空间中的next指针设置为NULL
		pt->next->next=NULL;
	}
}

bool IsExist(int x, int y)
{
	int key=(x*x+y*y)%PRIME;
	hashtab *pt=&(ht[key]);

	while (1)
	{
		if ((pt->x==x) && (pt->y==y))
			return true;
		else
		{
			if (pt->next != NULL) pt=pt->next;
			else return false;
		}
	}
}

//回收链表的空间,否则会造成内存泄漏。当然,在oj上影响不大。
void DestroyLinkList()
{
	hashtab *pt;
	stack<hashtab *> recycle;
	for (int i=0; i<PRIME; ++i)
	{
		pt=&(ht[i]);
		//找到链的末尾结点,从后向前回收。可是没有prev指针怎么办呢?用栈啦!
		while (pt->next != NULL)	//说明还不是链上的最后一个结点
		{
			recycle.push(pt);
			pt=pt->next;
		}

		//接下来把栈里面的指针指向的空间都回收就OK了
		while (!recycle.empty())
		{
			pt=recycle.top();
			delete (pt->next);
			recycle.pop();
		}
	}
}

int main()
{
	freopen("D:\\in.txt", "r", stdin);
	freopen("D:\\out.txt", "w", stdout);

	int n, cnt;

	while (1)
	{
		scanf("%d", &n);
		if(n==0) break;

		cnt=0;
		InitHashTab();

		BuildPointAndHashTab(n);

		//开始扫描点对
		for (int i=0; i<n; ++i)
		{
			for (int j=i+1; j<n; ++j)
			{
				int x1=p[i].x;	int y1=p[i].y;
				int x2=p[j].x;	int y2=p[j].y;
				int dx=x1-x2;	int dy=y1-y2;

				int x31=x1+dy;	int y31=y1-dx;
				int x41=x2+dy;	int y41=y2-dx;

				if(IsExist(x31, y31) && IsExist(x41, y41))	++cnt;

				int x32=x1-dy;	int y32=y1+dx;
				int x42=x2-dy;	int y42=y2+dx;

				if(IsExist(x32, y32) && IsExist(x42, y42))	++cnt;
			}
		}

		printf("%d\n", cnt/4);

		DestroyLinkList();
	}

	return 0;
}


哈希表正方形 摘一下题目: 正方形 总时间限制: 3500ms 内存限制: 65536kB 描述 给定直角坐标系中的若干整点寻找可以由这些组成正方形统计它们的个数。 输入 包括多组数据,每组数据的第一行是整点个数n(1<=n<=1000),其后n行每行由两个整数组成,表示一个的x、y坐标。输入保证一组数据中不会出现相同的,且坐标的绝对值小于等于20000。输入以一组n=0的数据结尾... 阅读详情

相关推荐

算法竞赛入门经典 第二章 循环

数据统计2题目:输入一些整数,求出最小值,最大值,平均值(保留三位小数),保证这些数都不超过1000 输入: 输入包含多组数据,每组数据第一行是整数个数n,第二行是n个整数。n=0为结束标记,程序应当忽略这组数据。相邻两组数据间应输出一个空行 样例输入: 8 2 8 3 5 1 7 3 6 4 -4 6 10 0 0 样例输出 Case 1: 1 8 4.375 (空行) Ca

Corleone_Yu的博客 523

leetcode正方形坐标-Leetcoding:日常练习

leetcode正方形坐标 Leetcoding practice 1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target,你在该数组中找出 和为目标值 target 的那 两个 整数,返回它们的数组下标。 2. 两数相加 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,且每个节只能存储 一位 数字。 你将两个数相加,以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。示例如下: 输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807. 3. 最长字串 给定一个字符串,你找出其中不含有重复字符的 最长子串的长度,示例如下: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3 4. 中位数 给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。你找出返回这两个正序数组的中位数。 输入:nums1 = [1,3], num

POJ - 2002Squares

POJ - 2002Squares 来源: 标签: 参考资料: 相似题目: 题目 A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is also a polygon such that ...

WINGREZ‘S BLOG 562

正方形

正方形Time Limit: 1000MS Memory Limit: 65536KB Problem Description给出四个,判断这四个能否构成一个正方形。 Input 输入的第一行包含一个整数T(T≤30)表示数据组数,每组数据只有一行,包括8个整数x1, y1, x2, y2,x3,y3,x4,y4(数据均在-1000,1000 之间)以逆时针顺序给出四个的坐标。 Outpu

Pruett的博客 934

正方形poj

包括多组数据,每组数据的第一行是整点个数n(1<=n<=1000),其后n行每行由两个整数组成,表示一个的x、y坐标。输入保证一组数据中不会出现相同的,且坐标的绝对值小于等于20000。输入以一组n=0的数据结尾。给定直角坐标系中的若干整点寻找可以由这些组成正方形统计它们的个数。对于每组输入数据,输出一个数,表示这组数据中的可以组成正方形的数量。

liubingchen52的博客 727

二分 poj2002 Squares

很有意义的一道二分题 题意:给出,问有多少个正方形 因为n 很容易就想到枚举正方形的两个,那么可以通过这两个可以得到对应的另外两个,那么如何验证这两个是否存在呢 当然会想到二分。先将坐标读入后排序好,然后用二分查询是否存在就可以了 难正方形不一定是平行坐标轴的,可能是斜的,所以如何用两个已知求得另外两个呢? 这里有个公式可以用来变换 d

qwb的博客 1686

[POJ2002]Squares【平面几何】

[POJ2002]Squares 题目大意 每组数据给你一个平面,平面上有N个,选取其中4个使之组成一个正方形(不重复,不一定平行于x,y轴),问你有几种方法? 解题报告 我们知道如果确定三个,就能确定一个正方形。确定两个就能确定两个正方形,且这两个正方形对称,对称轴是过两个的直线。那么我们就枚举两个,剩下两个就能推出来,然后用二分...

aiweiluan5095的博客 183

[POJ 2002]Squares[二分][数学]

题目链接:[POJ 2002]Squares[二分][数学] 题意分析: 平面中有n个,求这些组成多少个正方形? 解题思路: 最多1e3个,四个枚举肯定超时,必须控制在两个以内。那么两个可行吗?下面这幅图可以说明可行: 当一条边确定以后,由等边三角形的特性,旁边的两个也能枚举出来。 所以有(i是a,j是b): temp.x = p[i].x + (p[i]

闲停 1074

POJ 2002 Squares

题目链接:https://vjudge.net/problem/POJ-2002 题目大意   多组数据,每组给定 n 个不同的,问从这 n 个中选 4 个,使之能连成正方形,有多少种不同的选法? 分析   思路是枚举 2 个,然后计算出可能的另外两个,看它们存不存在。   最优解应该是用哈希表(O(n2))做,不过POJ万年不更新,都不能用 unordered_map...

weixin_30646315的博客 137

POJ2002Squares

http://poj.org/problem?id=2002 题意 : 就是给你很多的坐标,任取四个,看能组成多少个不同的正方形,相同的四个,不同顺序构成的正方形视为同一正方形。 思路 : 就是一个简单的枚举,但是你要是四个四个的枚举因为数据量到1000,所以肯定会超时的,就两个两个枚举,再去判断另外两个是否存在就可以了,百度了才知道有这样一个公式,知道两个(x1,y1)(x2...

weixin_30433075的博客 141

POJ 2002, Squares

Time Limit: 3500MSMemory Limit: 65536KTotal Submissions: 6320Accepted: 2024 DescriptionA square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is ...

weixin_34249678的博客 261

poj 2002 Squareshash

poj 2002 Squares 给出n个,问能组成多少个正方形? 题解: 先把每个hash 然后枚举两(即枚举正方形的一条边),然后通过三角形全等,可以推出正方形的另外两,在hash表里查找这两看是存在,存在则 Cnt +1。 最后 answer = Cnt/4 //因为同一正方形统计了4次。 #include #include #in

天亮说晚安 1714

POJ - 2002Squares

POJ - 2002Squares A square is a 4-sided polygon whose sides have equal length and adjacent sides form 90-degree angles. It is also a polygon such that rotating about its centre by 90 degrees gives the same po

The wind of freedom blows 305

【模拟】正方形

题目描述 有n个大小不一的正方形,现将它们依次以45度斜放入第一象限,每个正方形都要与x轴有一个交,且不能与之前放入的正方形重叠。在此前提下,正方形与x轴交的坐标应尽可能小。问这样放置后,从上往下看,至少能部分被看见的正方形有哪些? 输入格式 每个测试包含多组测试数据。每个测试数据的第一行是一个整数n,第二行是n个正整数,表示每个正方形的变长。输入以一行单独的0结束

wakawaka 1139

斐波那契数列

#include #include int ibonacci(int n); int main () { int n; scanf("%d",&n); int relust=ibonacci(n); printf("%d",relust); return 0; } int ibonacci(int n) { int a[n]; if(n<=0) exit(0); if

DangoTinker的博客 261

七.刷题.5

输入一些整数,求出它们的最大值,最小值和平均值(保留3位小数)。输入保证这些数都是不超过1000的整数。 输入包含多组数据,每组数据第一行是整数个数n,第二行是n个整数。n = 0为输入结束标记,程序应当忽略这组数据。相邻两组数据之间输出一个空行。 样例输入: 8 2 8 3 5 1 7 3 6 样例输出: Case 8:1 8 4.375 #include<stdio.h>...

JiangYu200015的博客 376

【2023】数据统计

2023:【例4.8】数据统计 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 10246 通过数: 3902 【题目描述】 输入一些整数,求出它们的最小值、最大值和平均值(保留3位小数)。输入保证这些数都是不超过1000的整数。 【输入】 一行,若干个整数。 【输出】 一行,即,最小值、最大值和平均值(保留3位小数)。 分析:1....

LWX3289765163的博客 2084
上一篇: poj1035 Spell Checker
下一篇: poj1703 Find them, Catch them
mach7
博客等级 码龄15年 32粉丝 50原创
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值