POJ2002 Squares Hash表+正方形顶点计算

该题的思路就是枚举所有的点,当然这么枚举要做到不能够重复和遗漏,所以我们约定值枚举对角线的两个点,最后将最终的结果除以2来计算。

由于每次通过枚举对角线的两个点,我们还要计算出另外两个顶点的坐标,所以这里用了一个很牛的公式,直接作加减法就能够出来了,判定下是否为整数。理论上我们马上要到点集中去寻找有没有这两个点,显然这种做法的效率很低,所以这里要用hash表,将顶点的信息的查询优化到接近O(1)。

这里把正方形计算另外两个顶点的公式记录如下(已知x1, x2, y1, y2, 求x3, y3, x4, y4):

  x1 + x2 = x3 + x4;

  y2 -  y1 = x4 -  x3;

  y1 + y2 = y3 + y4;

  x2 -  x1 = y3 -  y4;

代码如下:

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAXN 30001
#define MOD 30001
using namespace std;

int N, head[MAXN], idx;

struct Point
{
    int x, y;
}p[10005];

struct Node
{
    int x, y, next;
}e[10005];

void Hash(int x, int y)
{
    int key = abs(x * y) % MOD;
    ++idx;
    e[idx].x = x, e[idx].y = y;
    e[idx].next = head[key];
    head[key] = idx;
}

bool find(int x, int y)
{
    int key = abs(x * y) % MOD, ans = 0;
    for (int i = head[key]; i != -1; i = e[i].next) {
        if (e[i].x == x && e[i].y == y) {
            return true;
        }
    } 
    return false;
}

int main()
{
    int ans;
    while (scanf("%d", &N), N) {
        memset(head, 0xff, sizeof (head));
        idx = -1;
        ans = 0;
        for (int i = 0; i < N; ++i) {
            scanf("%d %d", &p[i].x, &p[i].y);    
            Hash(p[i].x, p[i].y);
        }
        double x1, y1, x2, y2;
        for (int i = 0; i < N; ++i) {
            for (int j = i+1; j < N; ++j) {
                x1 = ( (p[i].x + p[j].x) + (p[j].y - p[i].y) ) / 2.;
                x2 = ( (p[i].x + p[j].x) - (p[j].y - p[i].y) ) / 2.;
                y1 = ( (p[j].y + p[i].y) - (p[j].x - p[i].x) ) / 2.;
                y2 = ( (p[j].y + p[i].y) + (p[j].x - p[i].x) ) / 2.;
                if (x1 == floor(x1) && x2 == floor(x2) && y1 == floor(y1) && y2 == floor(y2)) {
                    if (find(x1, y1) && find(x2, y2)) {
                        ++ans;
                    } 
                }
            }
        }
        printf("%d\n", ans >> 1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Lyush/p/2587759.html