#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了。