kuangbin基礎計算幾何C - Segments (判斷直線和線段相交)
阿新 • • 發佈:2018-11-10
題目大意:給出n條線段兩個端點的座標,問所有線段投影到一條直線上,如果這些所有投影至少相交於一點就輸出Yes!,否則輸出No!。
解題思路:如果有存在這樣的直線,過投影相交區域作直線的垂線,該垂線必定與每條線段相交,問題轉化為問是否存在一條線和所有線段相交。
顯然所求線段若存在,那麼一定可以通過移動使其卡到2個端點上。
所以,列舉所有端點,判斷該直線是否合法。
坑點:
1.同一條線段的2個端也需要列舉,因為可能所有線段共線
2.判斷所列舉的直線是否退化為點。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<cmath> #define ll long long #define IOS {ios::sync_with_stdio(0);cin.tie(0);} using namespace std; const int N = 200; const double eps=1e-8; const double pi=acos(-1.0); int sgn(double x){ if(fabs(x)<eps) return 0; if(x<0) return -1; else return 1; } struct P{ double x,y; P(){} P(double a,double b){x=a;y=b;} P operator - (P b) const{ return P(x-b.x,y-b.y); } double operator ^ (P b) const{ return x*b.y-y*b.x; } double operator * (P b) const{ return x*b.x+y*b.y; } void transXY(double B){ double tx=x,ty=y; x=tx*cos(B)-ty*sin(B); y=tx*sin(B)-ty*cos(B); } }s[2*N]; struct L{ P s,e; L(){} L(P _s,P _e){ s = _s;e = _e; } }line[N]; bool L_inter_Seg(L l1,L l2){ //判斷直線和線段是否相交 return sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e))<=0; } int main(){ IOS; int T; cin>>T; while(T --){ int n,i,j,k; cin>>n; for(i = 1;i <= n;i ++){ cin>>line[i].s.x>>line[i].s.y; cin>>line[i].e.x>>line[i].e.y; s[i*2-1] = line[i].s; s[i*2] = line[i].e; } bool flag=0; for(i = 1;i <= 2*n;i ++) for(j = i+1;j <= 2*n;j ++){ L now(s[i],s[j]); if(s[i].x==s[j].x&&s[i].y==s[j].y) continue; for(k = 1;k <= n;k ++) if(!L_inter_Seg(now,line[k])) break; if(k==n+1) flag = 1; } if(flag)cout<<"Yes!"; else cout<<"No!"; cout<<endl; } return 0; }
```