POJ-3130 How I Mathematician Wonder What You Are!
阿新 • • 發佈:2018-11-24
operator 更新 算法 opera [1] oid poj can 交點
半平面交第一題 !
題意是給出一個多邊形,問他是否存在內核,即“可以看到任何一個地方的區域”。
內核即半平面交,下面是離線求半平面交的\(nlogn\)算法
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100; struct Point{ double x,y; Point(double xx=0,double yy=0){ x=xx,y=yy; } }a[maxn],p[maxn]; struct Vector{ double x,y; Vector(double xx=0,double yy=0){ x=xx,y=yy; } }; struct Line{ Point p; Vector v; double ang; Line(Point a=Point(),Vector b=Vector()){ p=a,v=b; ang=atan2(b.y,b.x); } }b[maxn],q[maxn]; int dcmp(double x){return fabs(x)<1e-9?0:(x>0?1:-1);} Vector operator - (Point a,Point b){return Vector(a.x-b.x,a.y-b.y);} Point operator + (Point a,Vector b){return Point(a.x+b.x,a.y+b.y);} Vector operator * (double p,Vector a){return Vector(a.x*p,a.y*p);} Vector operator * (Vector a,double p){return Vector(a.x*p,a.y*p);} double operator * (Vector a,Vector b){return a.x*b.y-a.y*b.x;} bool operator < (Line a,Line b){return a.ang<b.ang;} bool onleft(Line a,Point b){return dcmp(a.v*(b-a.p))>0;} Point glt(Point a,Point b,Point c,Point d){ Vector v1=b-a,v2=d-c,v3=a-c; return a+v2*v3/(v1*v2)*v1; } int n,l,r; void bpm(){ sort(b+1,b+n+1); l=r=1; q[1]=b[1]; //先加入第一條 for(int i=2;i<=n;i++){ while(l<r&&!onleft(b[i],p[r-1])) r--; while(l<r&&!onleft(b[i],p[l])) l++; //如果不在左邊就彈出去 q[++r]=b[i]; if(dcmp(b[i].v*q[r-1].v)==0){ r--; if(onleft(q[r],b[i].p)) //這個應該是如果兩個重合,就先把b[i]加入 q[r]=b[i]; } if(l<r) p[r-1]=glt(q[r-1].p,q[r-1].p+q[r-1].v,q[r].p,q[r].p+q[r].v); //交點更新 } while(l<r&&!onleft(q[l],p[r-1])) r--; //有可能最後加入的幾條是不合法的,要彈出來 } int main(){ // freopen("3130.in","r",stdin); while(1){ scanf("%d",&n); if(n==0) break; for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); for(int i=1;i<n;i++) b[i]=Line(a[i],a[i+1]-a[i]); b[n]=Line(a[n],a[1]-a[n]); bpm(); if(r-l<=1) printf("0\n"); else printf("1\n"); } return 0; }
POJ-3130 How I Mathematician Wonder What You Are!