计算几何
这题大概的意思就是,给你一系列的线段,问存不存在那么一条直线,当所有的线段向这条直线上投影的时候,投影能够有至少一个交点。
脑洞:投影的事情,我们可以用一条直线来表示方向,表示所有的线段沿着这个直线的某个方向进行投影(投影直线将与这条直线相垂直)。 那么至少有一个交点就变成了,能不能找到一条直线,将所有的线段串在一起?
接下里的任务是找这样的一条直线,这样的直线我们应该从各个线段的端点开始,找边沿的直线。
那么如何判断 这条直线与线段是否相交? 注意,题目给出的是四个点,没有直线的方程。
用向量吧。
从叉乘的定义来看 可以发现一下结论。我们只要保证那个角度与180度的关系即可。
那么根据题意 只要 这两个叉乘的乘积满足大于esp(1e-8),就是不满足题意的,这里算进了三点共线的情况。
好像这叫一次跨立实验? 那么线段与线段是否相交呢? 那就两次跨立实验就完成了吧。
然后这道题就是 点的枚举和直线的枚举了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define eps 1e-6
#define len 10010
using namespace std;
struct line{
double x1, y1, x2, y2;
line(){}
line(double _x1, double _y1, double _x2, double _y2):x1(_x1), y1(_y1), x2(_x2) ,y2(_y2){}
};
line l[len];
int n;
double cross(line a, double x, double y){
return (a.x1 - x) * (a.y2 - y) - (a.x2 - x) * (a.y1 - y);
}
bool check(double x1, double y1, double x2, double y2){
if ((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) < eps) return false;
line a(x1, y1, x2, y2);
for (int i=0; i<n; i++){
if (cross(a, l[i].x1, l[i].y1) * cross(a, l[i].x2, l[i].y2) > eps) return false;
}
return true;
}
int main(){
int T; scanf ("%d", &T);
while (T--){
scanf("%d", &n);
for (int i=0; i<n; i++) scanf("%lf%lf%lf%lf", &l[i].x1, &l[i].y1 ,&l[i].x2, &l[i].y2);
if (n==1) {
printf("Yes!\n");
continue;
}
bool flag = false;
for (int i=0; i<n; i++){
for (int j=i+1; j<n; j++){
if (check(l[i].x1, l[i].y1, l[j].x1, l[j].y1) ||
check(l[i].x1, l[i].y1, l[j].x2, l[j].y2) ||
check(l[i].x2, l[i].y2, l[j].x1, l[j].y1) ||
check(l[i].x2, l[i].y2, l[j].x2, l[j].y2))
flag = true;
if (flag) break;
}
if (flag) break;
}
if (flag) printf("Yes!\n");
else printf("No!\n");
}
return 0;
}