//题意:给一个t表示多组输入,每次输入一个坐标,x,y,问这些坐标功能组成多少个正方形。
//思路:将四个顶点枚举会超时,所以任意枚举两个点将另两个点算出来判断是否在自己创建的hash表里即可。那么按照什么规则枚举呢,如下图:这是我手动画的一个图,x1,x2也就是枚举已知的点,当然y1,y2与之对应没在途中写出来。那么我们只以至两个点为边不以这两个点为对角线。其实很好想我们将所有的两个点都枚举一次,那么无论是对角线组成的正方形还是边枚举最终都会被枚举且不会遗漏,而且都以边枚举有规律可循。
我们看我们已知的点也就是枚举的点是(x1,y1),(y1,y2),以x1x2为边有两个正方形,那么x3 = x2 + (y1-y2) 或 x3 = x2 - (y1-y2); y3 = y2 + (x2-x1) 或 y3 = y2 - (x2-x1); x4 = x1 + (y1-y2) 或 x4 = x1 - (y1-y2);y4 = y1 + (x2-x1) 或 y4 = y1- (x2-x1);仔细看一下很好理解的,无论(x1,y1), (x2, y2)位于那个位置,都满足这个规律,则可以构造hash表了,见代码(代码与图是对应的,因此很容易理解):
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct node{ //点的属性 int x, y; }node_[1005]; int Hash[1500]; //总共就1000组数字,1500够用了 node key_value[1500]; //每个键所对应的值 void insert_hash(int x, int y) { int mod = (x * x + y * y) % 1499; while(Hash[mod]){ mod = (mod + 1) % 1499; } key_value[mod].x = x; key_value[mod].y = y; Hash[mod] = 1; return ; } bool search_hash(int x, int y) { int mod = (x * x + y * y) % 1499; while(Hash[mod]){ if(key_value[mod].x == x && key_value[mod].y == y) return true; else mod = (mod + 1) % 1499; } return false; } int main() { int n; while(scanf("%d", &n) != EOF && n){ //init memset(Hash, 0, sizeof(Hash)); for(int i = 0; i < n; i++){ scanf("%d%d", &node_[i].x, &node_[i].y); insert_hash(node_[i].x, node_[i].y); } //calculate int x3, x4, y3, y4; int cnt = 0; for(int i = 0; i < n-1; i++){ for(int j = i+1; j < n; j++){ //i,j分别代表1,2 x3 = node_[j].x + (node_[i].y - node_[j].y); y3 = node_[j].y + (node_[j].x - node_[i].x); x4 = node_[i].x + (node_[i].y - node_[j].y); y4 = node_[i].y + (node_[j].x - node_[i].x); if(search_hash(x3, y3) && search_hash(x4, y4)) cnt++; x3 = node_[j].x - (node_[i].y - node_[j].y); y3 = node_[j].y - (node_[j].x - node_[i].x); x4 = node_[i].x - (node_[i].y - node_[j].y); y4 = node_[i].y - (node_[j].x - node_[i].x); if(search_hash(x3, y3) && search_hash(x4, y4)) cnt++; } } printf("%d\n", cnt/4); } return 0; }