POJ 2653 Pick-up sticks <<判断线段交
题意
求与上方的线段都没有交集的线段
思路
暴力判断线段交即可。
判断线段交的方法:
1.快速排斥实验
如图,如果两条线段不相交,他们所组成的矩形也不相交,而判断矩形相交是很方便的,用这个方法可以快速筛掉一些线段。
当然这并不是充要条件,两矩形相交也可能线段不相交。
所以矩形不相交是线段不相交的充分非必要条件。
2.那么正常的判断线段交方法:向量叉积,也就是跨立实验
线段相交,也就是说线段$P_1P_2$跨过了线段$Q_1Q_2$,同样,$Q_1Q_2$跨过了$P_1P_2$,所以有$(\overrightarrow{P_1P_2}\times\overrightarrow{P_1Q_1})\cdot (\overrightarrow{P_1P_2}\times\overrightarrow{P_1Q_2})<=0$使得$Q_1Q_2$跨过了$P_1P_2$
同理,有$(\overrightarrow{Q_1Q_2}\times\overrightarrow{Q_1P_1})\cdot (\overrightarrow{Q_1Q_2}\times\overrightarrow{Q_1P_2})<=0$使得$P_1P_2$跨过了$Q_1Q_2$
代码
1 #include<algorithm> 2 #include<cstdio> 3 using namespace std; 4 const int maxn=1e5+7; 5 const double eps=1e-8; 6 struct Point{ 7 double x,y; 8 }; 9 struct Segment{ 10 Point a,b; 11 }seg[maxn]; 12 double cross(Point p,Point a,Point b) 13 { 14 //cout<<p.x<<","<<p.y<<";"<<a.x<<","<<a.y<<";"<<b.x<<","<<b.y<<endl; 15 Point pa={a.x-p.x,a.y-p.y}; 16 Point pb={b.x-p.x,b.y-p.y}; 17 double ret=pa.x*pb.y-pa.y*pb.x; 18 //cout<<ret<<endl; 19 return ret; 20 } 21 bool intersect(Segment l1,Segment l2) 22 { 23 return 24 max(l1.a.x,l1.b.x) >= min(l2.a.x,l2.b.x) && 25 max(l2.a.x,l2.b.x) >= min(l1.a.x,l1.b.x) && 26 max(l1.a.y,l1.b.y) >= min(l2.a.y,l2.b.y) && 27 max(l2.a.y,l2.b.y) >= min(l1.a.y,l1.b.y) && 28 cross(l1.a,l2.a,l1.b)*cross(l1.a,l2.b,l1.b) <= 0 && 29 cross(l2.a,l1.a,l2.b)*cross(l2.a,l1.b,l2.b) <= 0; 30 } 31 int main() 32 { 33 int n; 34 while(~scanf("%d",&n)&&n) 35 { 36 for(int i=0;i<n;i++) 37 { 38 scanf("%lf%lf%lf%lf",&seg[i].a.x,&seg[i].a.y,&seg[i].b.x,&seg[i].b.y); 39 } 40 printf("Top sticks:"); 41 for(int i=0;i<n-1;i++) 42 { 43 for(int j=i+1;j<n;j++) 44 { 45 if(intersect(seg[i],seg[j])) 46 goto next; 47 } 48 printf(" %d,",i+1); 49 next:; 50 } 51 printf(" %d.\n",n); 52 53 } 54 }