题目来源:
http://noi.openjudge.cn/ch0305/1807/
http://poj.org/problem?id=2002
总时间限制: 8000ms 单个测试点时间限制: 4000ms 内存限制: 65536kB
描述
给出平面上一些点的坐标,统计由这些点可以组成多少个正方形。注意:正方形的边不一定平行于坐标轴。
输入
输入包括多组测试数据。每组的第一行是一个整数n (1 <= n <= 1000),表示平面上点的数目,接下来n行,每行包括两个整数,分别给出一个点在平面上的x坐标和y坐标。输入保证:平面上点的位置是两两不同的,而且坐标的绝对值都不大于20000。最后一组输入数据中n = 0,这组数据表示输入的结束,不用进行处理。
输出
对每组输入数据,输出一行,表示这些点能够组成的正方形的数目。
样例输入
4
1 0
0 1
1 1
0 0
9
0 0
1 0
2 0
0 2
1 2
2 2
0 1
1 1
2 1
4
-2 5
3 7
0 0
5 2
0
样例输出
1
6
1
来源
翻译自RockyMountain 2004的试题
-----------------------------------------------------
思路
将输入的点存在数组和map中,数组是为了顺序遍历,map是为了查找快(O(logN)). 取正方形对角线上的两个顶点,根据简单的几何关系计算另外一条对角线上两个顶点,若计算出的另外两个顶点都在map中,则找到一个正方形。因为两条对角线各被计算了一次,因此结果要除以2.
特别注意的是已知对角线AC上的a, c坐标,求b点坐标的公式为
bx = (ax+cx+cy-ay)/2
by = (ay+cy+ax-cx)/2
由于所有坐标都是int存储的,所以如果(ax+cx+cy-ay)和(ay+cy+ax-cx)不是2的倍数,bx,by也可能计算出在map中的值。所以要首先判断(ax+cx+cy-ay)和(ay+cy+ax-cx)是不是2的倍数,如果是2的倍数才可能和map中的其他点构成正方形。
然后就是C++里的map是用红黑树实现的,查询的复杂度为O(logN). 在NOI上能过,在POJ上会TIMELIMIT EXCEED. 为了进一步降低查询的复杂度,需要用hash map, hash map查询复杂度近似O(1). 可以用C++自己写hashmap,例如博文NOI 3.5 哈希 1551: Sumsets,偷懒的做法是用Java中的HashSet. 当然其实也挺麻烦的,因为节点类node要重写hashCode和equals方法,而且Java本身跑得慢,在POJ上也只是可以压着时间线过。
-----------------------------------------------------
代码
C++版_map实现
#include
#include
#include
Java版_HashSet实现
import java.util.HashSet;
import java.util.Scanner;
import java.util.Vector;
public class Main {
public static Vector vec = new Vector();
public static HashSet hm = new HashSet();
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int i,j,n,ans;
Scanner sc = new Scanner(System.in);
int xx,yy,x1,x2,x3,x4,y1,y2,y3,y4;
while (true)
{
n=sc.nextInt();
if (n==0)
{
break;
}
vec.clear();
hm.clear();
for (i=0; i