poj2002 排序+哈希

/**
 * poj 2002 排序+哈希
 * 首先要有一个正确的大方向,就是取两个点,利用公式给出另外两个点,并搜索这另外的两个点是否存在
 * 大方向有了,首先是确定另外两个点的方法,随意取点,可能组出多个正方形,判断的时候会取多次,这就浪费了很多运算量
 * 吸取了别人代码的经验,首先将点先x后y升序排列,然后对于i<j,只考虑yi>=yj的点。有所改进的是,我们这里不需要对xi==xj的情况多做判断,这是因为排序之后,不可能有xi==xj,yi>=yj的情况出现
 * 这样,得到两点取另两点的方向就可以放在第一象限方向(正方向)了
 * 下面是哈希,其实是就是哈希的原理,只是我是第一次手写哈希的构造和搜索,所以写出来很蹩脚。而且因为最开始,多轮运算之间忘了重新初始化HASH表,WA了好多次
 * 既然是第一次写哈希,就把哈希的原理也说一下吧.简单地说,我们用数组索引指向数据,而搜索的时候是用数据查找索引,哈希就是另外构建了一张表,将数据通过函数计算出一个下标,将原数组的索引作为值,以链表的形式存起来
 * 对于不可能出现哈希值重复的情况,就不需要使用链表,而像题目中这种情况,肯定会有重复的,就需要用链表来在重复的情况下进行查找。如何将整个数据范围尽量平摊到哈希表长度上,就是哈希函数选取的关键了
 * 我这里是随便取的,找了一个素数7993,取((abs(x)+1)*(abs(y)+1))%7993作为哈希函数,还好,344ms就过了
 * 这道题好像还有一种二分搜索的做法,我这里就不尝试了
 */
#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;
const int MAX_NUM = 1001;
const int PRIME = 7993;

struct point{
    int x;
    int y;
} p[MAX_NUM];

struct node{
    int index;
    node* next;
    node(){
        index = -1;
        next = NULL;
    }
    node(int i){
        index = i;
        next = NULL;
    }
};

int abs(int i){
    return (i>=0) ? i : -1*i;
}

int cmp(const void* a,const void* b){
    point *p1=(point*)a,*p2=(point*)b;
    if(p1->x != p2->x){
        return p1->x - p2->x;
    }
    else{
        return p1->y - p2->y;
    }
}

bool find(node* hash,int x,int y){
    int key = ((abs(x)+1) * (abs(y)+1)) % PRIME;
    node *pn;

    if(hash[key].index < 0){
        return false;
    }
    else{
        pn = &hash[key];
        while(pn != NULL){
            if(p[pn->index].x == x && p[pn->index].y == y){
                return true;
            }
            else{
                pn = pn->next;
            }
        }
        return false;
    }
}

int main(){
    int n,res;
    scanf("%d",&n);
    while(n!=0){
        node hash[PRIME];
        int key;
        node *pp;
        for(int i=0;i<n;++i){
            scanf("%d%d",&p[i].x,&p[i].y);
        }

        qsort(p,n,sizeof(point),cmp);

        for(int i=0;i<n;++i){
            //construct hash table
            key = ((abs(p[i].x)+1) * (abs(p[i].y)+1)) % PRIME;
            if(hash[key].index == -1){
                hash[key].index = i;
            }
            else{
                pp = &hash[key];
                while(pp->next != NULL){
                    pp = pp->next;
                }
                pp->next = new node(i);
            }
        }

        res = 0;
        int x1,x2,y1,y2,x3,x4,y3,y4,ydiff,xdiff;
        for(int i=0;i<n;++i){
            x1 = p[i].x;
            y1 = p[i].y;
            for(int j=i+1;j<n;++j){
                if(p[j].y <= p[i].y){
                    x2 = p[j].x;
                    y2 = p[j].y;
                    ydiff = abs(y1-y2);
                    xdiff = abs(x1-x2);
                    x3 = x1 + ydiff;
                    x4 = x2 + ydiff;
                    y3 = y1 + xdiff;
                    y4 = y2 + xdiff;
                    if(find(hash,x3,y3) && find(hash,x4,y4)){
                        ++res;
                    }
                }
            }
        }
        printf("%d\n",res);
        scanf("%d",&n);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值