1 条题解
-
0
这段代码解决的是"线段投影覆盖"问题,核心是判断是否存在一条直线使得所有线段在该直线上的投影至少有一个公共点。
算法原理
问题转化:存在一条直线L,使得所有线段在L上的投影至少有一个公共点 ↔ 存在一条直线L',与所有线段都相交。 关键思路: 几何对偶:若存在直线L'与所有线段相交,则L'的垂线方向即为所求投影直线L的方向。 候选方向筛选:只需检查由所有线段端点构成的直线方向,因为最优解必能通过旋转使得直线L'经过两个端点。
判定条件: 叉积判别:若线段AB在直线CD的同侧,则叉积AC×AD与BC×BD同号。 边界处理:排除两点重合的退化情况。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define eps 1e-8 #define maxn 110 struct Line { double x1,y1,x2,y2; void input(double a,double b,double c,double d) { x1=a,y1=b,x2=c,y2=d; } }L[maxn]; int n; int sgn(double x) { return x<-eps?-1:x>eps?1:0; } double dis(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double cross(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) { if(dis(x1,y1,x2,y2)<eps) return 0; for(int i=0;i<n;i++) if(cross(x1,y1,x2,y2,L[i].x1,L[i].y1)*cross(x1,y1,x2,y2,L[i].x2,L[i].y2)>eps) return 0; return 1; } int main() { int t; double a,b,c,d; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&a,&b,&c,&d); L[i].input(a,b,c,d); } if(n==1) { printf("Yes!\n"); continue; } int ans=0; for(int i=0;i<n&&!ans;i++) for(int j=i+1;j<n&&!ans;j++) if( judge(L[i].x1,L[i].y1,L[j].x1,L[j].y1) || judge(L[i].x1,L[i].y1,L[j].x2,L[j].y2) || judge(L[i].x2,L[i].y2,L[j].x1,L[j].y1) || judge(L[i].x2,L[i].y2,L[j].x2,L[j].y2)) ans=1; if(ans) printf("Yes!\n"); else printf("No!\n"); } return 0; }
- 1
信息
- ID
- 2305
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者