hihocoder #1040 : 矩形判断 #java

时间限制: 1000ms
单点时限: 1000ms
内存限制: 256MB

描述

给出平面上4条线段,判断这4条线段是否恰好围成一个面积大于0的矩形。

输入

输入第一行是一个整数T(1<=T<=100),代表测试数据的数量。

每组数据包含4行,每行包含4个整数x1, y1, x2, y2 (0 <= x1, y1, x2, y2 <= 100000);其中(x1, y1), (x2,y2)代表一条线段的两个端点。

输出

每组数据输出一行YES或者NO,表示输入的4条线段是否恰好围成矩形。

样例输入
3
0 0 0 1
1 0 1 1
0 1 1 1
1 0 0 0
0 1 2 3
1 0 3 2
3 2 2 3
1 0 0 1
0 1 1 0
1 0 2 0
2 0 1 1
1 1 0 1
样例输出
YES
YES
NO
解题思路
1:首先矩形必须是4个点。依次读取4条线段的2个点,进入map,key设为"x,y",重复的点会覆盖点。所以最后剩下4个点才继续向下判断,否则输出NO;
2:接下来判断四条线段之间是否平行或垂直。只需要拿边L1依次和其他三条边L2,L3,L4判断就可以了。
但是这时候有很多特殊情况,有4个点,4条边也平行或垂直,但也不一定构成矩形,如下图所示。我给的方法是,如果平行了,则不能有重合的点,平行边数量parallelNum加一;如果垂直了,则只有一个重合点,重合边数量verticalNum加一。
突然想起我忘记考虑【给出的一条边的两个点相同】,这个判断也简单,自己处理吧

代码:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
public class Main {
	ArrayList<Line> linesArray; //
	public int[] result;  // 判断结果
	
	public void entry(){
		Scanner sc = new Scanner(System.in);
		int number = sc.nextInt();
		int[][][] lines = new int[number][4][4];  // 线段坐标
		result = new int[number];
		// input
		for( int i=0; i<number; i++ ){
			for( int j=0; j<4; j++ ){
				for( int k=0; k<4; k++ ){
					lines[i][j][k] = sc.nextInt();
				}
			}
		}
		// judge
		for( int i=0; i<number; i++ ){		
			// 判读是否是4个点
			if( pointsJudge(i, 4, lines[i]) == false ){
				continue;
			}
			// 判断线段平行或垂直
			linesJudge(i, linesArray);		
		}	
		// output
		for(  int i=0; i<number; i++ ){
			if( result[i] == 1 ){
				System.out.println("YES");
			}
			else{
				System.out.println("NO");
			}
		}	
	}
	
	//  判断是否是 4 Points
	public boolean pointsJudge(int rectangleNumber, int lineNumber, int[][] lines){
		linesArray = new ArrayList<Line>();  // 线段数组
		HashMap<String, Point> pointsMap = new HashMap<String, Point>();  // 点Map
		for( int i=0; i<lineNumber; i++ ){
			Line line = new Line(lines[i]);
			linesArray.add(line);
			Point point1 = line.getPoint1();  // p1
			String key1 = point1.getKey();
			pointsMap.put(key1, point1);
			Point point2 = line.getPoint2();  // p2
			String key2 = point2.getKey();
			pointsMap.put(key2, point2);
		}	
		if( pointsMap.size() != 4 ){  // 不是4个点
			result[rectangleNumber] = 0;
			return false;
		}
		return true;
	}
	// 线段平行,垂直判断
	public int linesJudge(int rectangleNumber, ArrayList<Line> linesArray){	
		int x1 = linesArray.get(0).x1;
		int y1 = linesArray.get(0).y1;
		int x2 = linesArray.get(0).x2;
		int y2 = linesArray.get(0).y2;
		int verticalNum = 0;  // 垂直的线段数量
		int parallelNum = 0;  // 平行的线段数量
		
		for( int i=1; i<linesArray.size(); i++ ){
			int x3 = linesArray.get(i).x1;
			int y3 = linesArray.get(i).y1;
			int x4 = linesArray.get(i).x2;
			int y4 = linesArray.get(i).y2;
			// 判断垂直
			if( (y1-y2)*(y3-y4) == -1*(x1-x2)*(x3-x4) ){
				// 垂直了,还得有一个点重复
				if( (x1==x3)&&(y1==y3) || (x1==x4)&&(y1==y4) || (x2==x3)&&(y2==y3) || (x2==x4)&&(y2==y4) ){
					verticalNum++;
					continue;
				}else{
					result[rectangleNumber] = 0;
					return 0;
				}
			}
			// 判断平行
			if( (y1-y2)*(x3-x4) == (y3-y4)*(x1-x2) ){
				// 平行了,还得不能有点重复
				if( (x1==x3)&&(y1==y3) || (x1==x4)&&(y1==y4) || (x2==x3)&&(y2==y3) || (x2==x4)&&(y2==y4) ){
					result[rectangleNumber] = 0;
					return 0;
				}else{
					parallelNum++;
					continue;
				}
			}	
			// 既不平行也不垂直
			result[rectangleNumber] = 0;
		}
		if( verticalNum==2 && parallelNum==1 ){  // 两垂直一平行
			result[rectangleNumber] = 1;
		}
		return 1;
	}
	
	public static void main(String[] args){
		Main m = new Main();
		m.entry();
	}
	
	//
	class Line{
		int x1, y1, x2, y2;
		Line(int[] line){
			this.x1 = line[0];
			this.y1 = line[1];
			this.x2 = line[2];
			this.y2 = line[3];
		}
		Point getPoint1(){
			return new Point(this.x1, this.y1);
		}
		Point getPoint2(){
			return new Point(this.x2, this.y2);
		}
		String getKey(){
			return this.x1+","+this.y1+","+this.x2+","+this.y2;
		}
	}
	//
	class Point{
		int x, y;
		Point(int x, int y){
			this.x = x;
			this.y = y;
		}
		int getX(){
			return this.x;
		}
		int getY(){
			return this.y;
		}
		String getKey(){
			return this.x+","+this.y;
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值