poj 1410

来源:互联网 发布:java语言发展史 编辑:程序博客网 时间:2024/05/18 03:28

      这是一个很不错的模版题,题意也很明了,判断线段是否和矩形相交。而所谓“相交”,在计算几何的角度来看,就是线段有一点在矩形内或矩形上。判断的方法如下:

      判断线段的两端点是否在矩形内,若是,则线段在矩形内。

      判断线段是否与矩形相交,即是否和矩形的四条边中的任意一条边相交(规范相交和不规范相交都算)。

 

      此处是用有向面积法判断点是否在多边形内。最后,看看discuss。。。那个矩形的点有点XXXX,记得x1,x2 和 y1,y2的大小要分别判断,该交换的要交换。

 

      抄了pkkj神的模版,由无限wa瞬间1Y~~~

 

      以下是代码:

 

  1. #include<cstdio>
    #include<cmath>
    #include<iostream>
    using namespace std;
    const double eps=1e-8;
    struct point
    {
     double x,y;
    };
  2. struct line
    {
     point p1,p2;
    }l;
  3. struct poly
    {
     int n;
     double area;
     point plist[15];
    }rec;
  4. //点乘
  5. double dotdel(double x1,double y1,double x2,double y2)
    {
     return x1*x2+y1*y2;
    }
  6. //叉乘
  7. double crossmul(double x1,double y1,double x2,double y2)
    {
     return x1*y2-x2*y1;
    }
  8. //判断是否为0,达到一定精度即认为成立
  9. int cmpzero(double d)
    {
     return (fabs(d)<eps)?0:(d>0?1:-1);
    }
  10. //右手螺旋定则,1:a在cd右侧,-1:a在cd左侧,0:三点共线
  11. int cross(point a,point c,point d)
    {
     return cmpzero(crossmul(a.x-c.x,a.y-c.y,d.x-c.x,d.y-c.y));
    }
  12. //在cross(a,c,d)==0的基础上,可判断点a是否在cd内部
  13. int between(point a,point c,point d)
    {
     return cmpzero(dotdel(c.x-a.x,c.y-a.y,d.x-a.x,d.y-a.y))!=1;
    }
  14. //两线段相交情况:0:不相交,1:规范相交,2:不规范相交(交于端点或重合)
  15. int seg_intersect(point a,point b,point c,point d)
    {
     int a_cd=cross(a,c,d);
     if(a_cd==0 && between(a,c,d))
      return 2;
     int b_cd=cross(b,c,d);
     if(a_cd==0 && between(a,c,d))
      return 2;
     int c_ab = cross(c, a, b);
        if (c_ab == 0 && between(c, a, b))
            return 2;
     int d_ab=cross(d,a,b);
     if(d_ab==0 && between(d,a,b))
      return 2;
     if((a_cd^b_cd)==-2 && (c_ab^d_ab)==-2)
      return 1;
     return 0;
    }
  16. //使用有向面积法判断点是否在多边形内
  17. bool point_in_poly(point p)
    {
     double s=0.0;
     for(int i=0;i<rec.n;i++)
      s+=fabs(crossmul(rec.plist[i].x-p.x,rec.plist[i].y-p.y,rec.plist[(i+1)%rec.n].x-p.x,
      rec.plist[(i+1)%rec.n].y-p.y));
     if(cmpzero(s-rec.area)==0) return true;
     else return false;
    }
  18. //判断线段是否与多边形相交
  19. bool rec_seg_intersect()
    {
     if(point_in_poly(l.p1) && point_in_poly(l.p2))
      return 1;
     else if(seg_intersect(l.p1,l.p2,rec.plist[0],rec.plist[1])
      || seg_intersect(l.p1,l.p2,rec.plist[1],rec.plist[2])
      || seg_intersect(l.p1,l.p2,rec.plist[2],rec.plist[3])
      || seg_intersect(l.p1,l.p2,rec.plist[3],rec.plist[0]))
      return 1;
     return 0;
    }
  20. //计算多边形面积
  21. void getarea()
    {
     double s=rec.plist[0].y*(rec.plist[rec.n-1].x-rec.plist[1].x);
     for(int i=1;i<rec.n;i++)
      s+=rec.plist[i].y*(rec.plist[i-1].x-rec.plist[(i+1)%rec.n].x);
     rec.area=s;
    }
  22. int main()
    {
     int T;
     double x1,y1,x2,y2,t;
     scanf("%d",&T);
     while(T--)
     {
      scanf("%lf%lf%lf%lf",&l.p1.x,&l.p1.y,&l.p2.x,&l.p2.y);
      scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
      if(x1>x2)
      {t=x1;x1=x2;x2=t;}
      if(y2>y1)
      {t=y1;y1=y2;y2=t;}
      rec.n=4;
      rec.plist[0].x=x1;rec.plist[0].y=y1;
      rec.plist[1].x=x1;rec.plist[1].y=y2;
      rec.plist[2].x=x2;rec.plist[2].y=y2;
      rec.plist[3].x=x2;rec.plist[3].y=y1;
      getarea();
      puts(rec_seg_intersect()?"T":"F");
     }
     return 0;
    }
原创粉丝点击