NOI 3.5 哈希 1807:正方形

题目来源:

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,这组数据表示输入的结束,不用进行处理。

输出

对每组输入数据,输出一行,表示这些点能够组成的正方形的数目。

扫描二维码关注公众号,回复: 1710294 查看本文章

样例输入

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要重写hashCodeequals方法,而且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;
	}
}

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80774811