1 条题解

  • 0
    @ 2025-5-1 17:03:39

    该问题需要判断给定线段是否与矩形相交,属于计算几何中的线段相交检测问题。代码实现主要分为以下几个步骤:

    1. 矩形边界处理: • 将矩形的四个顶点坐标调整为规范形式(确保xleftxrightx_{\text{left}} \leq x_{\text{right}}ybottomytopy_{\text{bottom}} \leq y_{\text{top}})。

      • 将矩形的四条边表示为四条线段:

      ◦ 左边:(x1,y1)(x_1, y_1)(x1,y2)(x_1, y_2)

      ◦ 右边:(x2,y1)(x_2, y_1)(x2,y2)(x_2, y_2)

      ◦ 下边:(x1,y1)(x_1, y_1)(x2,y1)(x_2, y_1)

      ◦ 上边:(x1,y2)(x_1, y_2)(x2,y2)(x_2, y_2)

    2. 线段完全包含检测: • 若线段的两个端点(xstart,ystart)(x_{\text{start}}, y_{\text{start}})(xend,yend)(x_{\text{end}}, y_{\text{end}})均满足:

      $ x_1 \leq x \leq x_2 \quad \text{且} \quad y_1 \leq y \leq y_2 $ 则线段完全位于矩形内部,直接判定为相交(输出TT)。

    3. 线段与矩形边相交检测: • 使用跨立实验(Cross Product Test)判断线段是否与矩形的任意一条边相交:

      ◦ 对于两条线段ABABCDCD,计算叉积:

    Cross(A,B,C)Cross(A,B,D)0Cross(A,B,C)⋅Cross(A,B,D)≤0Cross(C,D,A)Cross(C,D,B)0Cross(C,D,A)⋅Cross(C,D,B)≤0 ◦ 若满足上述条件,则两线段相交。

    • 若线段与任意一条矩形边相交,判定为相交(输出TT),否则不相交(输出FF)。

    关键点说明

    1. 规范矩形坐标: • 通过交换x1x_1x2x_2y1y_1y2y_2,确保x1x2x_1 \leq x_2y1y2y_1 \leq y_2,从而统一矩形的表示形式。

    2. 跨立实验的边界处理: • 代码中通过sgn函数处理浮点数精度问题,避免因精度误差导致误判。

      • 特殊处理线段端点位于另一线段上的情况(OnSegment函数)。

    3. 完全包含检测优先: • 先检查线段是否完全在矩形内部,可提前终止计算,提升效率。

    代码实现

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include <cstdio>
    using namespace std;
    #define ll long long
    int n;
    struct Point
    {
        double x,y;
        Point(double x= 0, double y = 0):x(x),y(y){}
    }p[1000];
    typedef Point Vector;
    const int INF = 0x3f3f;
    Vector operator-(Point A,Point B)
    {
        return Vector(A.x-B.x,A.y-B.y);
    }
    Vector operator *(Vector A, double p)
    {
        return Vector(A.x*p, A.y*p);
    }
    Vector operator +(Vector A, Vector B){
        return Vector(A.x+B.x, A.y+B.y);
    }
    Vector operator /(Vector A, double p){return Vector(A.x/p, A.y/p);}
    double Dot(Vector A, Vector B){ return A.x*B.x + A.y*B.y;}
    double Length(Vector A){ return sqrt(Dot(A, A));}
    double Cross(Vector A, Vector B){return A.x*B.y-A.y*B.x;}
    double dis(Point a,Point b)
    {
        return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
    }
    const double eps = 1e-6;
    int sgn(double x){
        if(fabs(x) < eps)
            return 0;
        if(x < 0)
            return -1;
        return 1;
    }
    struct Line{
        Point v, p;
        Line(){}
        Line(Point v, Point p):v(v), p(p){}
        Point point(double t){
            return v+(p-v)*t;//·µ»ØµãP = v + (p - v)*t
        }
    }line[105000];
    int dcmp(double x){
        if(fabs(x) < eps)
            return 0;
        if(x < 0)
            return -1;
        return 1;
    }
    bool OnSegment(Point p, Point a1, Point a2){
        return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
    }
    bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
        double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
        double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
        //if判断控制是否允许线段在端点处相交,根据需要添加
        if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
            bool f1 = OnSegment(b1, a1, a2);
            bool f2 = OnSegment(b2, a1, a2);
            bool f3 = OnSegment(a1, b1, b2);
            bool f4 = OnSegment(a2, b1, b2);
            bool f = (f1|f2|f3|f4);
            return f;
        }
        return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
    }
    void swap(double &a, double &b)
    {
        if(a>b)
        {
            double temp = a;
            a = b;
            b = temp;
        }
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
        while(n--)
        {
            double x1, x2, y1, y2;
            Point st, ed;
            scanf("%lf%lf%lf%lf", &st.x, &st.y, &ed.x, &ed.y);
            scanf("%lf%lf%lf%lf",&x1, &y1, &x2, &y2);
            swap(x1,x2);
            swap(y1,y2);
    
            line[1] = Line(Point(x1,y1), Point(x1,y2));
            line[2] = Line(Point(x2,y1), Point(x2,y2));
            line[3] = Line(Point(x1,y1), Point(x2,y1));
            line[4] = Line(Point(x1,y2), Point(x2,y2));
          
    
            line[5] = Line(st,ed);
            if(st.x >=x1&&st.x <=x2 && st.y >=y1 && st.y <=y2 && ed.x >=x1 &&ed.x <=x2 && ed.y>=y1 &&ed.y <=y2)
            {
                printf("T\n");
            }
            else
            {
                bool flag = false;
                for(int i = 1;i<=4;i++)
                {
                    if(SegmentProperIntersection(line[i].v, line[i].p, line[5].v, line[5].p))
                    {
    
                        flag = true;
                        break;
                    }
                }
                if(flag)
                    printf("T\n");
                else
                    printf("F\n");
            }
    
        }
        return 0;
    }
    • 1

    信息

    ID
    411
    时间
    2000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者