一. 原题链接: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();
}
}