poj 3304 Segments(判斷直線與線段相交)
阿新 • • 發佈:2018-11-05
題目連結:poj 3304
題目大意:給出n條線段兩個端點的座標,問所有線段投影到一條直線上,如果這些所有投影至少相交於一點就輸出Yes!,否則輸出No!。
解題思路:
如果存在L的話,能說明什麼。。說明L的法線L’肯定能經過所有的線段
若存在一條直線L‘能經過所有線段,說明存在L’經過所有線段的兩個端點。
直線肯定經過兩個端點。
那麼我們只要列舉兩個端點P1P2,對每個直線P1P2 遍歷所有線段i:1~N,用叉積<=0來判斷線段的兩個端點L1L2是否在P1P2的兩側,如果找到一組P1P2就能輸出YES了
向量P和向量Q,假如 P*Q>0 ,P在Q的順時針,P*Q<0,則P在Q的逆時針,P*Q=0,則P與Q共線。
(L1P1^L1P2 )*(L2P1^L2P2 )<=0 ^代表外積,如下圖
注意:要判斷重複點,即P1P2有可能重點,那麼只要加判一下就好了。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; struct point { double x,y; point(){} point(double _x,double _y){ x=_x;y=_y; } }; point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);} point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);} point operator * (point a,double p) { return point(a.x*p,a.y*p);} point operator / (point a,double p){ return point(a.x/p,a.y/p);} struct line{ point S,E; line(){} line(point _a,point _b){ S=_a;E=_b; } }segment[110]; bool operator < (const point &a,const point &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); } const double esp=1e-8; int dcmp(double x){ if(fabs(x)<esp) return 0; else return x<0?-1:1; } bool operator ==(const point &a,const point &b){ return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double Cross(point a,point b) { return a.x*b.y-a.y*b.x;} double area2(point a,point b, point c) {return Cross(b-a,c-a);} double Dot(point A,point B) { return A.x*B.x+A.y*B.y;}///2,點積,即是|a||b|*cos<a,b>,可用來判斷角度的範圍 double Length(point A) {return sqrt(Dot(A,A));} ///兩點之間的距離 int n; bool check(line A) { if(dcmp(Length(A.E-A.S))==0) return 0; for(int i=0;i<n;i++) ///判斷該直線A是否相交所有線段 { if(dcmp(area2(segment[i].S,A.S,A.E))*dcmp(area2(segment[i].E,A.S,A.E))>0) return false; } return true; } int main() { int ncase; scanf("%d",&ncase); double x1,y1,x2,y2; while(ncase--) { scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); segment[i]=line(point(x1,y1),point(x2,y2)); } bool flag=false; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { ///列舉兩條線段i,j的某兩個端點作為直線 if(check(line(segment[i].S,segment[j].S))||check(line(segment[i].S,segment[j].E)) ||check(line(segment[i].E,segment[j].S))||check(line(segment[i].E,segment[j].E))){ flag=true; break; } } } if(flag) puts("Yes!"); else puts("No!"); } return 0; }