题目链接:https://vjudge.net/problem/POJ-3304
题意:求是否能找到一条直线,使得n条线段在该直线的投影有公共点。
思路:
如果存在这样的直线,那么在公共投影点作直线的垂线,显然该垂线会经过所有直线,那么原题转换为求是否有经过所有线段的直线。
如果存在这样的直线,那么该直线一定能通过平移和旋转之后经过所有线段中的两个端点,那么我们枚举所有两两线段的端点作为直线的两点,然后是判断直线是否经过所有线段。如果线段为p0p1,直线为p2p3,那么相交时满足:(p0p2^p0p3)*(p1p2^p1p3)<=0。总复杂度为O(n^3)。
AC code:
#include<cstdio> #include<algorithm> #include<cmath> #include<cstdlib> using namespace std; const int maxn=105; const double eps=1e-8; int T,n,flag; struct Point{ double x,y; Point(){} Point(double xx,double yy):x(xx),y(yy){} Point operator + (const Point& b)const{ return Point(x+b.x,y+b.y); } Point operator - (const Point& b)const{ return Point(x-b.x,y-b.y); } double operator * (const Point& b)const{ return x*b.x+y*b.y; } double operator ^ (const Point& b)const{ return x*b.y-b.x*y; } }; struct Line{ Point s,e; Line(){}; Line(Point ss,Point ee){ s=ss,e=ee; } }line[maxn]; int sgn(double x){ if(abs(x)<eps) return 0; if(x<0) return -1; return 1; } double dist(Point a,Point b){ return sqrt((b-a)*(b-a)); } double xmult(Point p0,Point p1,Point p2){ //p0p1 ^ p0p2 return (p1-p0)^(p2-p0); } bool seg_inter_line(Line l1,Line l2){ //判断直线l1和线段l2是否相交 return sgn(xmult(l2.s,l1.s,l1.e))*sgn(xmult(l2.e,l1.s,l1.e))<=0; } bool check(Point p1,Point p2){ if(sgn(dist(p1,p2))==0) return 0; Line l1=Line(p1,p2); for(int i=1;i<=n;++i) if(!seg_inter_line(l1,line[i])) return 0; return 1; } int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); flag=0; for(int i=1;i<=n;++i){ double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); line[i]=Line(Point(x1,y1),Point(x2,y2)); } for(int i=1;i<=n;++i){ for(int j=i;j<=n;++j) if(check(line[i].s,line[j].s)||check(line[i].s,line[j].e)|| check(line[i].e,line[j].s)||check(line[i].e,line[j].e)){ flag=1; break; } if(flag) break; } if(flag) printf("Yes! "); else printf("No! "); } return 0; }