题目来源:
http://noi.openjudge.cn/ch0305/1807/
http://poj.org/problem?id=2002
1807:正方形
总时间限制: 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<iostream> #include<fstream> #include<map> using namespace std; struct node { int x,y; bool operator < (const node &b) const // map用<来构建红黑树 { if (x==b.x) { return y<b.y; } else { return x<b.x; } } }; const int NMAX = 1005; const double EFS = 1e-5; int n; map<node, bool> mp; node vec[NMAX] = {}; int main() { #ifndef ONLINE_JUDGE ifstream fin ("0305_1807.txt"); int i,j,ans=0; int x1,x2,x3,y1,y2,y3,x4,y4; node nd,nd1; while (fin >> n) { if (n==0) { break; } mp.clear(); for (i=0; i<n; i++) { fin >> nd.x >> nd.y; vec[i] = nd; mp[nd] = 1; } ans = 0; for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) { x1 = vec[i].x; x2 = vec[j].x; y1 = vec[i].y; y2 = vec[j].y; if ((x1+x2+y2-y1)%2==0 && (y1+y2+x1-x2)%2==0 && (x1+x2+y1-y2)%2==0 && (y1+y2+x2-x1)%2==0) { x3 = (x1+x2+y2-y1)/2; y3 = (y1+y2+x1-x2)/2; nd.x = x3; nd.y = y3; x4 = (x1+x2+y1-y2)/2; y4 = (y1+y2+x2-x1)/2; nd1.x = x4; nd1.y = y4; if (mp[nd] && mp[nd1]) { ans++; } } } } ans /= 2; cout << ans << endl; } fin.close(); #endif #ifdef ONLINE_JUDGE int i,j,ans=0; int x1,x2,x3,y1,y2,y3,x4,y4; node nd,nd1; while (cin >> n) { if (n==0) { break; } mp.clear(); for (i=0; i<n; i++) { cin >> nd.x >> nd.y; vec[i] = nd; mp[nd] = 1; } ans = 0; for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) { x1 = vec[i].x; x2 = vec[j].x; y1 = vec[i].y; y2 = vec[j].y; if ((x1+x2+y2-y1)%2==0 && (y1+y2+x1-x2)%2==0 && (x1+x2+y1-y2)%2==0 && (y1+y2+x2-x1)%2==0) { x3 = (x1+x2+y2-y1)/2; y3 = (y1+y2+x1-x2)/2; nd.x = x3; nd.y = y3; x4 = (x1+x2+y1-y2)/2; y4 = (y1+y2+x2-x1)/2; nd1.x = x4; nd1.y = y4; if (mp[nd] && mp[nd1]) { ans++; } } } } ans /= 2; cout << ans << endl; } #endif }
Java版_HashSet实现
import java.util.HashSet; import java.util.Scanner; import java.util.Vector; public class Main { public static Vector<node> vec = new Vector<node>(); public static HashSet<node> hm = new HashSet<node>(); /** * @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<n; i++) { xx = sc.nextInt(); yy = sc.nextInt(); node nd = new node(xx,yy); vec.add(nd); hm.add(nd); } ans = 0; for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) { x1 = vec.get(i).x; x2 = vec.get(j).x; y1 = vec.get(i).y; y2 = vec.get(j).y; if ((x1+x2+y2-y1)%2==0 && (y1+y2+x1-x2)%2==0 && (x1+x2+y1-y2)%2==0 && (y1+y2+x2-x1)%2==0) { x3 = (x1+x2+y2-y1)/2; y3 = (y1+y2+x1-x2)/2; node nd1 = new node(x3,y3); x4 = (x1+x2+y1-y2)/2; y4 = (y1+y2+x2-x1)/2; node nd2 = new node(x4,y4); if (hm.contains(nd1) && hm.contains(nd2)) { ans++; } } } } ans /= 2; System.out.println(ans); } } } class node { public Integer x,y; public node(int xx, int yy) { x = xx; y = yy; } /** * 为了使用HashSet, 需要重写hashCode和equals方法 */ public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if(getClass() != obj.getClass()) return false; node other = (node)obj; if(!x.equals(other.x)) return false; if(!y.equals(other.y)) return false; return true; } public int hashCode() { int res = 1; res = 31*res + x; res = 31*res + y; return res; } }