• 题目大意
    • 给你n条线段,问是否存在这样一条直线,使得所有线段在直线上的投影均有公共部分
    • 有输出Yes 没有输出No
  • 题解
    • 投影直线上有公共点的话就是说这条直线存在一个垂线经过所有线段 就是与所有线段均相交
    • 只要枚举这些线段端点所确定的直线 是否存在一条与所有线段均相交即可
    • 判断线段相交用的是叉乘 首先用两点p1,p2确定了一条直线 在用p1,p2分别与计算线段两个端点计算叉乘即可
    • 叉乘之积>0就说明线段两端点在直线的同侧 也就是直线不经过此线段
    • 判断直线和线段相交,这个和判断线段和线段相交差不多,从直线上任取两个点,和线段的端点比较,如果两个在同一侧,那么就不相交,反之,就相交。关键问题就是怎么找这个直线, 假设存在一条直线跟所有线段都相交,我们可以让这个直线旋转,条件是旋转之后仍然相交,所有一定有个临界条件,而且这个临界条件一定发生在线段的端点处, 所以,可以通过枚举所有 线段端点的方式来求这个直线。
    • 还有需要注意的是:
      • 1.  n = 1, n = 2时要特判,因为2条线段一定可以找第三条直线与他们相交
      • 2. 如果枚举线段端点的时候,两个点的距离小于10^-8,那么就跳过此直线。由于计算机在浮点类型的计算中1e-8会当成三点共线来算,所以不能用它来当成要求的那条直线。本题是double类型,判断是否有重点,重点定义为坐标非常接近的两点 <1e-8即可,判断叉乘之积时,只要<1e-8 即可
    • https://blog.csdn.net/qq_33184171/article/details/51066516
    • https://www.bbsmax.com/A/MyJxabZ25n/
  • 代码
    • #include <iostream>
      #include <math.h>
      #include <cstdio>
      using namespace std;
      #define MAXM 110
      #define EPS 1e-8
      
      typedef struct{
          double x1,y1,x2,y2;
      }Segment;
      
      Segment segment[MAXM];
      int n;
      
      double distance(double x1,double y1,double x2,double y2){
          return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
      }
      
      double corss(double x1,double y1,double x2,double y2,double x,double y){
          return (x2-x1)*(y-y1)-(x-x1)*(y2-y1);
      }
      
      bool judge(double x1,double y1,double x2,double y2){
          int i;
          if(distance(x1,y1,x2,y2)<EPS) return 0;
          for(i=0;i<n;i++){
              if(corss(x1,y1,x2,y2,segment[i].x1,segment[i].y1)*
                  corss(x1,y1,x2,y2,segment[i].x2,segment[i].y2)>EPS) return 0;
          }
          return 1;
      }
      
      int main(){
          int t,i,j,ans;
          scanf("%d",&t);
          while(t--){
              scanf("%d",&n);
              for(i=0;i<n;i++)
                  scanf("%lf%lf%lf%lf",&segment[i].x1,&segment[i].y1,&segment[i].x2,&segment[i].y2);
              if(n==1) {printf("Yes!\n");continue;}
      
              ans=0;
              for(i=0;i<n && !ans;i++)
                  for(j=i+1;j<n && !ans;j++){
                      if(judge(segment[i].x1,segment[i].y1,segment[j].x1,segment[j].y1) ||
                          judge(segment[i].x1,segment[i].y1,segment[j].x2,segment[j].y2) ||
                          judge(segment[i].x2,segment[i].y2,segment[j].x1,segment[j].y1) ||
                          judge(segment[i].x2,segment[i].y2,segment[j].x2,segment[j].y2))
                          ans=1;
                  }
              if(ans) printf("Yes!\n");
              else printf("No!\n");
          }
          return 0;
      }

发表评论

邮箱地址不会被公开。 必填项已用*标注