题目可以转化成是否存在这样的一条直线,穿过所有的线段。这是很容易就能想到的。
然后,假如只有一个端点重合,那么我们可以知道,必定会有属于两条线段的某两个端点连出的直线可以穿过所有线段。这是枚举的思想。
那么,我们该怎么判定直线与线段有交点呢?不妨通过跨立的定义来做,这是经人点醒了才想到的。
在求线段是否有交点的时候用到过跨立,但我认为,跨立的定义应该是延长的线后是否存在交点(当前包括开始就存在交点的。)
假设枚举两点得到的线段是A1A2,判断是否有交点的线段是B1B2,则要求A1A2跨立B1B2。
设P1=向量(O->B1),P2=(O->B2),Q1=(O->A1),Q2=(O->A2);
则((P1-Q1)x(Q2-Q1))*((Q1-P2)x(Q2-Q1))>=0
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <cstdio> 5 #include <math.h> 6 #define eps 0.00000001 7 using namespace std; 8 9 typedef struct po{ 10 double x,y; 11 }Point; 12 13 typedef struct pl{ 14 Point start,end; 15 }Pleg; 16 int how_point,how_pleg; 17 Point pot[300]; 18 Pleg peg[300]; 19 Pleg Line; 20 21 bool dbcmp(double x,double y){ 22 if(fabs(x-y)<eps) return false; 23 return true; 24 } 25 26 double multi(Point a,Point b, Point c,Point d){ 27 return (a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x); 28 } 29 30 bool slove(int k){ 31 if(multi(peg[k].start,Line.start,Line.end,Line.start)*multi(Line.start,peg[k].end,Line.end,Line.start)>=0) 32 return true; 33 return false; 34 } 35 36 int main(){ 37 int T,n; 38 scanf("%d",&T); 39 while(T--){ 40 how_point=how_pleg=0; 41 scanf("%d",&n); 42 for(int i=1;i<=n;i++){ 43 scanf("%lf%lf",&pot[how_point].x,&pot[how_point].y); 44 peg[how_pleg].start=pot[how_point]; 45 how_point++; 46 scanf("%lf%lf",&pot[how_point].x,&pot[how_point].y); 47 peg[how_pleg].end=pot[how_point]; 48 how_point++; 49 how_pleg++; 50 } 51 bool flag=false; 52 for(int i=0;i<how_point;i++){ 53 for(int j=i+1;j<how_point;j++){ 54 if(!dbcmp(pot[i].x,pot[j].x)&&!dbcmp(pot[i].y,pot[j].y)) 55 continue; 56 Line.start=pot[i]; Line.end=pot[j]; 57 int k; 58 for(k=0;k<how_pleg;k++){ 59 if(slove(k)){ 60 continue; 61 } 62 break; 63 } 64 if(k==how_pleg){ 65 flag=true; 66 break; 67 } 68 } 69 if(flag) break; 70 } 71 if(flag) printf("Yes! "); 72 else printf("No! "); 73 } 74 return 0; 75 }