poj 2002 Squares 哈希

题意:给出平面上的n个点,求出能组成的正方形个数。(n <= 1000)

先考虑暴力,O(n^4),会超时。

再考虑正方形的特点,已知两个点,可以推出另外两个点。所以枚举两个点,因为点的坐标|x,y|<=200000,所以需要哈希处理。复杂度O(n^2)。

枚举两个点时,我曾经纠结于是否枚举对角线。但是细想一下,包含对角线的正方形其实应经在枚举过程中出现了,故不需要重复考虑。

枚举时要考虑两个方向的正方形。最后每个正方形枚举了4次。


关于哈希函数的选择,坐标的平方和产生的冲突较多,耗时较大,3000ms;用坐标和的话,922ms。

(关于点的检查,我也纠结了很久,就是新推出的点的哈希值是否会重合,或是它们怎么区分。最后,从大神们的博客找到答案,判断坐标是否一致。)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

typedef long long ll;

const int mod = 2e5 + 3;
const int maxn = 1001;

int n;
int hash[mod];
int rec[maxn], cnt;
int next[maxn];

struct Node {
        int x, y;
} node[maxn];

inline int Hash(int x, int y) {
        return abs(x + y);
}

inline void hashit(int i) {
        int p = Hash(node[i].x, node[i].y);
        if (hash[p] == -1) {
                hash[p] = i;
                next[i] = -1;
        }
        else {
                int j = hash[p];
                next[i] = next[j];
                next[j] = i;
        }
}

inline bool check(int x, int y) {
        int k = Hash(x, y);
        int p = hash[k];
        while (p != -1) {
                if (node[p].x == x && node[p].y == y) return true;
                p = next[p];
        }
        return false;
}

int main() {
        while (~scanf("%d", &n) && n) {
                for (int i = 0; i < n; i++) scanf("%d%d", &node[i].x, &node[i].y);
                memset(hash, -1, sizeof(hash));
                for (int i = 0; i < n; i++) hashit(i);
                // for (int i = 0; i < n; i++) printf("%d%c", next[i], " \n"[i == n - 1]);
                int ans = 0;
                int x, y, t, k;
                for (int i = 0; i < n - 1; i++)
                        for (int j = i + 1; j < n; j++) {
                                // printf("i:%d, j:%d\n", i, j);
                                int x1, x2, y1, y2, dx, dy;
                                x1 = node[i].x; y1 = node[i].y;
                                x2 = node[j].x; y2 = node[j].y;
                                if (x1 > x2) {
                                        int t = x1; x1 = x2; x2 = t;
                                        t = y1; y1 = y2; y2 = t;
                                }
                                dy = abs(y1 - y2);
                                dx = x2 - x1;
                                int a1, b1, a2, b2;
                                a1 = x1 + dy; a2 = x2 + dy;
                                if (y1 >= y2) {
                                        b1 = y1 + dx;
                                        b2 = y2 + dx;
                                }
                                else {
                                        b1 = y1 - dx;
                                        b2 = y2 - dx;
                                }
                                if (check(a1, b1) && check(a2, b2)) ans++;
                                // printf("%d\n", ans);
                                a1 = x1 - dy; a2 = x2 - dy;
                                if (y1 >= y2) {
                                        b1 = y1 - dx;
                                        b2 = y2 - dx;
                                }
                                else {
                                        b1 = y1 + dx;
                                        b2 = y2 + dx;
                                }
                                if (check(a1, b1) && check(a2, b2)) ans++;
                                // printf("%d\n", ans);
                        }
                printf("%d\n", ans >> 2);
        }
        return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值