1 条题解
-
0
该问题需要判断给定线段是否与矩形相交,属于计算几何中的线段相交检测问题。代码实现主要分为以下几个步骤:
-
矩形边界处理: • 将矩形的四个顶点坐标调整为规范形式(确保且)。
• 将矩形的四条边表示为四条线段:
◦ 左边:到
◦ 右边:到
◦ 下边:到
◦ 上边:到
-
线段完全包含检测: • 若线段的两个端点和均满足:
$ x_1 \leq x \leq x_2 \quad \text{且} \quad y_1 \leq y \leq y_2 $ 则线段完全位于矩形内部,直接判定为相交(输出)。
-
线段与矩形边相交检测: • 使用跨立实验(Cross Product Test)判断线段是否与矩形的任意一条边相交:
◦ 对于两条线段和,计算叉积:
且 ◦ 若满足上述条件,则两线段相交。
• 若线段与任意一条矩形边相交,判定为相交(输出),否则不相交(输出)。
关键点说明
-
规范矩形坐标: • 通过交换与、与,确保且,从而统一矩形的表示形式。
-
跨立实验的边界处理: • 代码中通过
sgn
函数处理浮点数精度问题,避免因精度误差导致误判。• 特殊处理线段端点位于另一线段上的情况(
OnSegment
函数)。 -
完全包含检测优先: • 先检查线段是否完全在矩形内部,可提前终止计算,提升效率。
代码实现
#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
- 上传者