您的位置:首页 > 其它

poj 2002 哈希和二分

2013-03-08 10:48 429 查看
Squares

Time Limit: 3500MSMemory Limit: 65536K
Total Submissions: 13153Accepted: 4870
Description

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 polygon. It is not the only polygon with the latter property, however,
as a regular octagon also has this property.

So we all know what a square looks like, but can we find all possible squares that can be formed from a set of stars in a night sky? To make the problem easier, we will assume that the night sky is a 2-dimensional plane, and each star is specified by its x
and y coordinates.

Input

The input consists of a number of test cases. Each test case starts with the integer n (1 <= n <= 1000) indicating the number of points to follow. Each of the next n lines specify the x and y coordinates (two integers) of each point. You may assume that the
points are distinct and the magnitudes of the coordinates are less than 20000. The input is terminated when n = 0.
Output

For each test case, print on a line the number of squares one can form from the given stars.
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

Source

Rocky Mountain 2004

算法过程:

1 将顶点按x坐标递增排序,若x相同,按y坐标递增排序,然后枚举所有边,对每一条由点p1和p2(根据排序p1 < p2)组成的边按照如下方式可唯一确定一个正方形:

1) 将边绕p1逆时针旋转90度得到点p3

2) 将边绕p2顺时针旋转90度得到点p4

则p1 p2 p3 p4组成一个正方形,设p1 = (x1,y1), p2 = (x2, y2),根据向量的旋转公式可以求出p3, p4的坐标为

p3 = (y1 - y2 + x1, x2 - x1 + y1)

p4 = (y1 - y2 + x2, x2 - x1 + y2)

2 然后搜索点p3和p4是否存在,若存在则找到一个正方形,计数加1,可以发现总是存在两条边确定的正方形是一样的,也就是说每个正方形会被发现2次,所以要将最后的计数结果除以2.

实现的时候关键是如何搜索某个点是否存在,由于所有点都排序过,所以可以用二分查找来搜索,但速度比较慢,至少1000ms, hash的速度更快些,可以达到几百ms,还有hash表如果用开放地址线性探测法解决冲突的话,很容易超时,

而用链地址法解决冲突效果要好很多。下面是二分搜索和hash两种方法的代码实现。

二分查找:
#include <iostream>
#include<stdio.h>
#include<vector>
using namespace std;
int n;//节点数
int sumAll;//正方形总数
typedef struct node
{
int x,y;

}node;
node allNode[2000];
int cmp(const void *a,const void *b)
{
node x1=*((node*)a);node y1=*((node*)b);
if (x1.x>y1.x)
{
return 1;
}
if (x1.x<y1.x)
{
return -1;
}
if (x1.x==y1.x&&x1.y>y1.y)
{
return 1;
}
if (x1.x==y1.x&&x1.y<y1.y)
{
return -1;
}
else return 0;
}
void init()
{

sumAll=0;
int i;
for(i=1;i<=n;i++)
{
scanf("%d%d",&allNode[i].x,&allNode[i].y);

}
qsort(&allNode[1],n,sizeof(allNode[1]),cmp);

}
bool finds(node x3)
{
int     m, s, t;

s = 1;
t = n;
while (s <= t) {
m = (s+t)/2;
if (allNode[m].x == x3.x && allNode[m].y == x3.y) return true;
if (allNode[m].x > x3.x || (allNode[m].x == x3.x && allNode[m].y > x3.y)) {
t = m-1;
}
else {
s = m+1;
}
}
return false;

}
bool query(node x1,node x2)
{
node x3,x4;
if (((x1.x)+(x2.x)+(x1.y)-(x2.y))%2!=0)
{
return false;
}

x3.x=((x1.x)+(x2.x)+(x1.y)-(x2.y))/2;
x3.y=((x1.y)+(x2.y)+(x2.x)-(x1.x))/2;
x4.x=((x1.x)+(x2.x)-(x1.y)+(x2.y))/2;
x4.y=((x1.y)+(x2.y)-(x2.x)+(x1.x))/2;
if (finds(x3)&&finds(x4))
{
return true;
}
return false;

}
void solve()
{
int i,j;
for (i = 1; i <=n; i++)
{
for (j = i+1; j<=n; j++)
{

if(query(allNode[i],allNode[j])==true)
{

sumAll++;
}
}
}
}
int main()
{
while(true)
{
cin>>n;
if(n==0)break;
init();
solve();
cout<<sumAll/2<<endl;

}
}



哈希算法:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define DEBUG

#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__)
#else
#define debug(...)
#endif

#define N 1000	/* 顶点个数 */
#define M 2999	/* hash表的大小,取素数冲突冲突较少 */

struct Point {
int x;
int y;
};

struct Point point
;

/* 使用链地址法解决冲突, 表头不存数据 */
struct hash_entry {
int x;
int y;
struct hash_entry *next;
};

struct hash_entry hash_table[M+1];

int conflict;

void insert(int x, int y)
{
unsigned int 	p;
struct hash_entry *new_entry;

p = (x*x+y*y)%M;	/* hash函数 */
//创建一个新的entry
new_entry = (struct hash_entry *)malloc(sizeof(struct hash_entry));
new_entry->x = x;
new_entry->y = y;
/* 把新entry插在最前面,这样,越先插进来的entry在链表的越后面,
*最后一个entry的next指针为空
*/
new_entry->next = hash_table[p].next;
hash_table[p].next = new_entry;
}

int find(int x, int y)
{
unsigned int 	p;
struct hash_entry *entry;

p = (x*x+y*y)%M;	/* hash函数 */
for(entry = hash_table[p].next; entry != 0 && (entry->x != x \
|| entry->y != y); entry = entry->next, conflict++);
if (entry) {
return 1;
}
return 0;
}

int main()
{
int 	n, x, y, i, j, count;

while (scanf("%d", &n), n) {
memset(hash_table, 0, sizeof(hash_table));
count = 0;
for (i = 0; i < n; i++) {
scanf("%d %d", &x, &y);
//插入法对点排序,按照x从小到大,y从小到大,且x优先排列的方式
for (j = i-1; j >= 0; j--) {
if (point[j].x > x || (point[j].x == x && point[j].y > y)) {
point[j+1] = point[j];
} else {
break;
}
}
point[j+1].x = x;
point[j+1].y = y;
insert(x, y);
}
/* 枚举所有边,对每条边的两个顶点可以
* 确定一个唯一的正方形,并求出另外两个顶点的坐标
*/
for (i = 0; i < n; i++) {
for (j = (i+1); j < n; j++) {
//计算第三个点的坐标,搜索其是否存在
x = point[i].y-point[j].y+point[i].x;
y = point[j].x-point[i].x+point[i].y;
if (!find(x, y)) {
continue;
}
//计算第四个点的坐标,搜索其是否存在
x = point[i].y-point[j].y+point[j].x;
y = point[j].x-point[i].x+point[j].y;
if (find(x, y)) {
count++;
}
}
}
printf("%d\n", count/2);
}
debug("conflict = %d\n", conflict);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: