POJ3304 Segments

一. 原题链接:http://poj.org/problem?id=3304

二. 题目大意:问是否存在一条直线使得平面上所有线段在这条直线上的投影有公共点。

三. 思路:等价于找一条直线与所有线段相交,直线上两点可通过枚举线段两两端点来寻找。

用叉乘判断线段与直线是否相交:

判断线段的2个端点分别在直线的哪一侧。

复杂度O(n3) n=100可过。

下面说一下为什么可以这样等价:

如果所要求直线存在:

(1)在所要求直线上找一个投影的公共点,过该点作直线的垂线,则该线必定和所有线段相交。

(2)平移所作出的直线直到不能再平移,达到某一线段端点,再旋转改直线直到不能再旋转,达到另一线段的端点。

四.代码:

import java.util.Scanner;

class Main {

	static int num;
	static final int MAX_SIZE = 110;
	static double[] x1 = new double[MAX_SIZE], y1 = new double[MAX_SIZE],
			x2 = new double[MAX_SIZE], y2 = new double[MAX_SIZE];
	
	//输入向量(x1, y1), (x2, y2)
	static double crossProduct(double x1, double y1, double x2, double y2){
		return x1*y2- x2*y1;
	}
	
	//输入直线上2点(x1, y1), (x2, y2)
	static boolean judgeLine(double lineX1, double lineY1, double lineX2, double lineY2){
		if (Math.abs(lineX1-lineX2) < 10e-8 &&
				Math.abs(lineY1-lineY2) < 10e-8)
			return false;
		for (int i = 0; i < num; i++){
			double v1x = lineX1 - x1[i], v1y = lineY1 - y1[i],
					v2x = lineX2 - x1[i], v2y = lineY2 - y1[i],
					v11x = lineX1 - x2[i], v11y = lineY1 - y2[i],
					v22x = lineX2 - x2[i], v22y = lineY2 - y2[i];
			if (crossProduct(v1x, v1y, v2x, v2y) *
					crossProduct(v11x, v11y, v22x, v22y) > 0){
				return false;
			}
		}
		return true;
	}
	
	public static void main (String args[]){
	
		Scanner in = new Scanner(System.in);
		int test = in.nextInt();
		while(test-- != 0){
				
			num = in.nextInt();
			for(int i = 0; i < num; i++){
				x1[i] = in.nextDouble();
				y1[i] = in.nextDouble();
				x2[i] = in.nextDouble();
				y2[i] = in.nextDouble();
			}
			
			boolean yse = false;
			for(int i = 0; i < num; i++){
				if (yse)
					break;
				for(int j = 0; j < num; j++){
					if(i != j){
						if (judgeLine(x1[i], y1[i], x2[j], y2[j]) || 
								judgeLine(x1[i], y1[i], x1[j], y1[j]) ||
								judgeLine(x2[i], y2[i], x2[j], y2[j]) ||
								judgeLine(x2[i], y2[i], x1[j], y1[j])){
							yse = true;
							break;
						}
					}
				}
			}
			
			if (yse || num == 1) {
				System.out.println("Yes!");
			} else {
				System.out.println("No!");
			}
		}
		in.close();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值