POJ - 2002(静态哈希链表找正方形)
第一次做OJ,卡了好久, 稍微总结下.
原理
注意如果正方形有两个点是整数, 余下的两个点一定是整数. 计算公式如下:
已知: (x1,y1),(x2,y2) 则:
x3=x1+(y1−y2)y3=y1−(x1−x2)
x4=x2+(y1−y2)y4=y2−(x1−x2)
或
x3=x1−(y1−y2)y3=y1+(x1−x2)
x4=x2−(y1−y2)y4=y2+(x1−x2)
注意:
- 此题不需要去用float或者double类型.
- 这种做法会使同一个正方形按照不同的顺序被枚举了四次,因此最后的结果要除以4.
- 如果只取上面一种情况,就对半分,除以2, 其实是错的:
如果我们把题意第一组测试实例4个点的顺序改变一下再输入,先不要除,会发现得到的的正方形的个数是不固定的,这就是由于输入的顺序照成的. 只能按照除4来计算.
基本思想:枚举每一条边(两个点),然后根据相应的公式求出另外两个点,利用哈希进行查找这两个点是否存在即可
实现细节(其实都是踩过的坑 T_T)
哈希表使用静态链表,这样不再需要开另外的链表, 直接用star数组的数据即可,有效的节省了空间. 使用的时候采取头插入.
哈希数组工作原理 : 下标为哈希值 h , 存储的是哈希值为
h 的点的索引, 如果有多个哈希值为 h 的点, 则存储最后插入点的索引(因为使用头插入)静态链表的使用:
创建
开两个数组, 第一个数组hash[]存放头结点, 第二个数组next[]存放下一个结点的索引. 索引是和数据数组star[]绑定的.
原本逻辑上的数据结构(注意这里的next指向的是相同hash值的下一个点,没有相同hash值时默认指向第0个元素, 也说明赋值和使用都不能用第0个元素, 静态链表千万不能用0!!!!!!):
struct point { int x; int y; int next; }; point star[1005];
因为我们要反复利用哈希静态链表, next值会频繁取出, 因此最为高效的方式应该是将next分离:
struct point { int x; int y; }; point star[1005]; int next[1005];
哈希表初始化用memset函数(在cstring类中), 可以减少操作时间. 如果让系统自动初始化会超时….
即 memset初始化耗时 < 自动初始化耗时
且全局变量在两种初始化同时存在时优先考虑memset函数.
memset函数使用注意事项:
- 只能初始化为0,或者-1(即000000…..或者fffffffff…….)
优先使用scanf,printf, 尽量不用cin, cout.
注意题中如果给出了多组数据在一个实例中, 说明要对输入进行循环处理……(好坑啊!)
关于
~scanf(...)
调用scanf这个函数的返回值是成功读取的数据个数。在你这段程序里,如果正确输入了,也就是成功读取了一个数据,scanf的返回值为1;如果没有正确输入,那成功读取的数据个数就是0,也就是scanf的返回值为0.~的意思是把数据的各个二进制位反转。在C语言里不等于0就表示真。如果scanf返回值为0,那~scanf(…)就是~0,是一个二进制位全部为1的数,在C里当然表示真;如果scanf返回值为1,那~scanf(…)就是~1,是一个只有最后一个二进制位为0其余二进制位全部为1的数,在C里同样表示真。不论输入正确与否都为真,循环都会继续,因此~scanf(…)不能用于表示没有正确输入。只有在遇到文件结束或者输入(Ctrl+D或者Ctrl+Z)时,scanf返回EOF,是个所有二进制位都为1的数,这时~scanf(…)就是~EOF,是一个所有二进制位都为0的数,也就是0,表示假,这时候循环才会结束。所以,~scanf(…)是表示没有遇到文件结束或者输入(Ctrl+D或者Ctrl+Z),当然这时候自然也不会有正确输入。来自 https://zhidao.baidu.com/question/464277961.html
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define MOD 20007
using namespace std;
struct point
{
int x;
int y;
};
point star[1005];
int next[1005];
int hash[MOD+5];
void insert(point a,int index)
{
int h = (a.x*a.x+a.y*a.y)%MOD;
next[index] = hash[h];//***************注意使用
hash[h] = index;
}
bool find(point a)
{
int h = (a.x*a.x + a.y*a.y) %MOD;
int p = hash[h];
while(p)
{
if(star[p].x==a.x && star[p].y==a.y)
return true;
p = next[p];//********************注意使用
}
return false;
}
int AIn(point a1, point a2)
{
int ans = 0;
point b1,b2;
int dx = (a1.x-a2.x);
int dy = (a1.y-a2.y);
b1.x = a1.x + dy;
b1.y = a1.y - dx;
b2.x = a2.x + dy;
b2.y = a2.y - dx;
if(find(b1) && find(b2))
ans++;
b1.x = a1.x - dy;
b1.y = a1.y + dx;
b2.x = a2.x - dy;
b2.y = a2.y + dx;
if(find(b1) && find(b2))
ans++;
return ans;
}
int main()
{
int n;
while( ~scanf("%d",&n) && n)
{
memset(hash,0,sizeof(hash));
memset(next,0,sizeof(next));
for (int i = 1; i <= n; i++)
{
scanf("%d%d",&star[i].x,&star[i].y);
insert(star[i],i);
}
int cnt = 0;
for (int i = 1; i <= n; i++)
for (int j = i+1; j <= n; j++)
cnt += AIn( star[i],star[j]);
printf("%d\n",cnt >> 2);
}
return 0;
}