原题地址 点击打开链接
题意: 给出n条线段两个端点的坐标,问所有线段投影到一条直线上,如果这些所有投影至少相交于一个点就输出Yes!,否则输出No!。
解题思路:如果有存在这样的直线,过投影相交区域作直线的垂线,该垂线必定与每条线段相交,问题转化为问是否存在一条直线和所有线段相交
若存在一条直线与所有线段相机相交,此时该直线必定经过这些线段的某两个端点,所以枚举任意两个端点即可。
直线与线段相交判断: 如下图, 设直线为AB, 线段为PQ, 利用叉积性质, 线段两端在直线的两旁, 即向量(BP x BA)* (BA x BQ) <=0
代码
#include <cstdio> #include <cmath> #include <iostream> #include <stdlib.h> using namespace std; #define esp 1e-8 struct point { double x1, y1, x2, y2; }p[105]; int n, flag; 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)<esp) return 0; //判断重复点 for(i=0;i<n;i++){ if(corss(x1,y1,x2,y2,p[i].x1,p[i].y1)* corss(x1,y1,x2,y2,p[i].x2, p[i].y2)>esp) //判断相交 return 0; } return 1; } int main() { int t, i, j; cin >> t; while(t--) { cin >> n; for(i=0; i<n;i++) { cin >> p[i].x1 >> p[i].y1 >> p[i].x2 >> p[i].y2; } if(n==1 || n==2) { printf("Yes!\n"); continue; } flag = 0; for(i=0; i<n;i++) { for(j=i+1; j<n; j++) { //枚举 if(judge(p[i].x1, p[i].y1, p[j].x1, p[j].y1) && !flag) flag = 1; if(judge(p[i].x2, p[i].y2, p[j].x1, p[j].y1)&& !flag) flag = 1; if(judge(p[i].x1, p[i].y1, p[j].x2, p[j].y2)&& !flag) flag = 1; if(judge(p[i].x2, p[i].y2, p[j].x2, p[j].y2)&& !flag) flag = 1; } } if(flag) printf("Yes!\n"); else printf("No!\n"); } return 0; system("pause"); }
COD