题目大意:
给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一点就输出Yes!,否则输出No!。
解题思路:
如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条线和所有线段相交
若存在一条直线与所有线段相交,此时该直线必定经过这些线段的某两个端点,所以枚举任意两个端点即可。
这里要主要的地方就是,题目说如果两个点的距离小于1e-8就等价于一点,所以要考虑重点
关于coross函数:
1.若函数的返回值为0,则 (x2-x1)*(y-y1)-(x-x1)*(y2-y1);即 (y-y1)/(x-x1)=(y2-y1)/(x2-x1); (直线斜率相等,k1=k2)
注意:(浮点数除法在计算的过程中会影响精度)
即 过(x,y),(x1,y1)的直线(直线斜率为k1)和过(x1,y1),(x2,y2)的直线(直线斜率为k2)平行
说明 (x,y)在过 (x1,y1),(x2,y2)的直线上
2.若返回值不为0,说明 (x,y)不在过 (x1,y1),(x2,y2)的直线上
①返回值小于0,(y-y1)/(x-x1)<(y2-y1)/(x2-x1);即 k1<k2
关于judge函数:
若(x1,y1),(x2,y2)不重合,判断过(x1,y1),(x2,y2)的直线是否和线段seg[i]相交1.coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)*coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)
若乘积的符号为正,则说明 过(x1,y1),(x2,y2)的直线和线段seg[i]不相交
2.coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)*coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)
若乘积的符号为负,则说明 过(x1,y1),(x2,y2)的直线和线段seg[i]相交
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const int MAX=105; const double EPS=1e-8;//EPS相当于0 struct node{ double x1,y1,x2,y2; }seg[MAX]; int n; double distance(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } //若两条直线斜率相等,则不相交 double coross(double x1,double y1,double x2,double y2,double x,double y) { return (x2-x1)*(y-y1)-(x-x1)*(y2-y1); //叉积 } //判断经过点(x1,y1),(x2,y2)的直线是否和所有的线段相交 bool judge(double x1,double y1,double x2,double y2) { if(distance(x1,y1,x2,y2)<EPS) return 0;//两点重合 for(int i=0;i<n;i++) { if(coross(x1,y1,x2,y2,seg[i].x1,seg[i].y1)* coross(x1,y1,x2,y2,seg[i].x2,seg[i].y2)>EPS) return 0; } return 1; } int main() { int t; scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%lf%lf%lf%lf",&seg[i].x1,&seg[i].y1,&seg[i].x2,&seg[i].y2); if(n==1){ printf("Yes!\n");continue; } bool ans=0; for(int i=0;i<n&&!ans;i++){ for(int j=i+1;j<n&&!ans;j++){ if( judge(seg[i].x1,seg[i].y1,seg[j].x1,seg[j].y1)|| judge(seg[i].x1,seg[i].y1,seg[j].x2,seg[j].y2)|| judge(seg[i].x2,seg[i].y2,seg[j].x1,seg[j].y1)|| judge(seg[i].x2,seg[i].y2,seg[j].x2,seg[j].y2) ) ans=1; } } if(ans) printf("Yes!\n"); else printf("No!\n"); } return 0; }