poj-2002

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

struct pointInfo {
    int x;
    int y;
    int havl;
    char used;
    char usedAsSquare;
};

struct point {
    int x;
    int y;
};

typedef struct pointInfo pointInfo;
typedef struct point point;

#define esp 1e-10

const int BIG_PRIME = 10007;
const int MAX_ADD = 20000;

point pointArray[1001];
pointInfo pointHashArray[10027];

int fillInHash(int x, int y) {
    int x1 = x + MAX_ADD;
    int y1 = y + MAX_ADD;
    int havl = (x1*x1 + y1*y1) % BIG_PRIME;
    int fillPos = havl;
    while(1) {
        if (!pointHashArray[fillPos].used) {
            pointHashArray[fillPos].x = x;
            pointHashArray[fillPos].y = y;
            pointHashArray[fillPos].havl = havl;
            pointHashArray[fillPos].usedAsSquare = 0;
            pointHashArray[fillPos].used = 1;
            return fillPos;
        } else {
            fillPos++;
            if (fillPos >= 1009) {
                fillPos = 0;
            }
        }
    }
}

int IfPointExist(int x, int y) {   // -1 no exist, else the pos in hashArray.
    int x1 = x + MAX_ADD;
    int y1 = y + MAX_ADD;
    int havl = (x1*x1 + y1*y1) % BIG_PRIME;
    int Pos = havl;
    char byPassOneRound = 0;
    while(1) {
        if (byPassOneRound && Pos == havl) {
            return -1;
        }
        if (!pointHashArray[Pos].used) {
            return -1;
        } else {
            if (pointHashArray[Pos].havl == havl) {
                if (pointHashArray[Pos].x == x &&
                    pointHashArray[Pos].y == y ) {
                    return Pos;
                }
            }
            Pos++;
            if (Pos >= BIG_PRIME) {
                byPassOneRound = 1;
                Pos = 0;
            }
        }
    }
}

void getSquareNum(int pointNum) {
    int squareNum = 0;
    for (int i = 0; i < pointNum-1; i++) {
        for (int j = i+1; j < pointNum; j++) {
            double x1 = pointArray[i].x;
            double x2 = pointArray[j].x;
            double y1 = pointArray[i].y;
            double y2 = pointArray[j].y;

            double x3 = (x1+x2+y2-y1)/2;
            double y3 = (y1+y2+x1-x2)/2;

            double x4 = (x1+x2-y2+y1)/2;
            double y4 = (y1+y2-x1+x2)/2;

            double len1=((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1))*2;
            double len2=((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
            if ((int)x3 != x3 ||
                (int)x4 != x4 ||
                (int)y3 != y3 ||
                (int)y4 != y4) {
                continue;
            }

            if(abs(len1-len2) > esp)
                continue;
            int Pos3 = IfPointExist(x3, y3);
            int Pos4 = IfPointExist(x4, y4);
            if (Pos3 != -1 && Pos4 != -1) {
                // printf("%f %f %f %f\n", x1, y1, x2, y2);
                // printf("%f %f %f %f\n", x3, y3, x4, y4);
                squareNum++;
            }
        }
    }
    printf("%d\n", squareNum/2);
    // printf("%d %d\n", squareNum, squareNum/2);
}

int main() {
    int pointNum = 0;
    while(scanf("%d", &pointNum)) {
        if (pointNum == 0) {
            return 0;
        }
        memset(pointArray, 0 , sizeof(pointArray));
        memset(pointHashArray, 0 , sizeof(pointHashArray));
        for (int i = 0; i < pointNum; i++) {
            scanf("%d %d", &(pointArray[i].x), &(pointArray[i].y));
            fillInHash(pointArray[i].x, pointArray[i].y);
        }
        getSquareNum(pointNum);
    }

}


G++ 312K 1438MS(hash数组开了10007) 1407Ms(hash数组开了20011). 后来试了拉链法, 4460K 1219MS, 数组直接开到了99999, 貌似提升的也不是特别多.

这道题的关键是要知道一个正方形的定点坐标方程:

正方形ABCD
A(X1,Y1), C(X3,Y3), 对角线。

那么,另外两个顶点坐标:

x2:=(x1+x3+y3-y1)/2; y2:=(y1+y3+x1-x3)/2;
x4:=(x1+x3-y3+y1)/2; y4:=(y1+y3-x1+x3)/2;

没想到还有个这么方便的方程, 本来还准备自己推来着.....

基本思路是这样的:

首先一条对角线就可以决定一个特定的正方形,那么对

对点数组做个两重遍历:

遍历每一个对角线, 然后用上面的方程求出另外一条对角线的两个顶点,再看这两个顶点是否存在于点数组即可。

这里怎么查看定点存在,既可以实现排好点数组,二分查找,也可以hash搞起。

我这里用了hash,一开始空间开了最小,只到1000(点的最大数量), 结果果然付出了时间的代价,直接TLE, 后来直接开了10007的,终于勉强AC.

还犯了低级错误,把1000改10007的时候,忘了把fill和get里面也同步改,结果WA了好几次....

要试试拉链法了,在某些情况,查找效率应该高点,尤其是检测某些点是否在hash数组中,正好3432基本一样,可以在3432上试试.

还有要注意的一点,也是一个优化点:

一个正方形有两个对角线,如果对于某一个对角线AB,其对应的另外一个对角线的两个点C,D是存在于点数组的,那么在以后的遍历中,还会遇到

CD作为对角线来检测正方形,会得到AB, 这种情况下,如果每次匹配正方形数量都加1,那么最后的结果要除以2才是正方形的数量(一个正方形的两条对角线都被算了一次)。

这也是一种效率的浪费,因为在检测完AB以后,CD在下次遍历到的时候,就不应该再进行检测了(查看hash数组是不小的开销). 看到有解法似乎实现排序可以避免,要再看看.

还有个优化就是,因为题目明确了输入的都是整数,那么在通过上面的方程得到的坐标值是小数,就可以直接pass了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值