poj 3525 Most Distant Point from the Sea(將邊內縮)(半平面交求多邊形中可以放入最大的圓的半徑)
阿新 • • 發佈:2018-11-25
題目連結:http://poj.org/problem?id=3525
題意:在凸邊形內找出一點,使得到多邊形邊界的距離最大。
題解:
參考部落格:https://blog.csdn.net/zuzhiang/article/details/78404556
轉化為求多邊形內可以放入的最大的圓的半徑。二分求解。
///半平面交 #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=111; struct point { double x,y; point(){} point(double _x,double _y){ x=_x;y=_y; } }poly[maxn];///儲存半平面交後的交點 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);} 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 P,point Q) { return P.x*Q.y-P.y*Q.x; } double Length(point A) { return sqrt(A.x*A.x+A.y*A.y);} struct LINE { point s,t; double angle; LINE(){} LINE(point _s,point _t){ s=_s;t=_t; angle=atan2(t.y-s.y,t.x-s.x); } }L[maxn],dq[maxn],trans[maxn];///儲存向量,半平面交時用到的雙端佇列dq point Getlinenode(LINE a,LINE b) { point P=a.s,v=a.t-a.s; ///點,向量 point Q=b.s,w=b.t-b.s; point u=P-Q; double t=Cross(w,u)/Cross(v,w); return P+v*t; } bool cmp(LINE P,LINE Q) ///兩向量方向相同,靠下的優先 { if(fabs(P.angle-Q.angle)<esp) return Cross(P.s-P.t,Q.s-P.t)>esp; return P.angle<Q.angle; } bool Onright(LINE L,point p){ ///判斷點p在直線L的右邊, return Cross(L.s-L.t,p-L.t)>esp; } int Half(int n,int &m) { sort(L,L+n,cmp); int l=0,r=1; m=1; for(int i=1;i<n;++i)///篩掉同斜率,保留靠下的向量,其餘不要 if(fabs(L[i].angle-L[i-1].angle)>esp)L[m++]=L[i]; n=m; m=0; dq[0]=L[0],dq[1]=L[1]; for(int i=2;i<n;++i) { if(dcmp(Cross(dq[r].s-dq[r].t,dq[r-1].s-dq[r-1].t))==0||dcmp(Cross(dq[l].s-dq[l].t,dq[l+1].s-dq[l+1].t))==0) return; ///交點在直線的右邊,捨去 while(l<r&&Onright(L[i],Getlinenode(dq[r],dq[r-1]))>0)--r; while(l<r&&Onright(L[i],Getlinenode(dq[l],dq[l+1]))>0)++l; dq[++r]=L[i]; } ///判斷下頭尾向量 while(l<r&&Onright(dq[l],Getlinenode(dq[r],dq[r-1]))>0)--r; while(l<r&&Onright(dq[r],Getlinenode(dq[l],dq[l+1]))>0)++l; if(r-l<=1) return 0; return 1; // dq[++r]=dq[l];///將頭向量加到尾部 // for(int i=l;i<r;++i) // poly[m++]=Getlinenode(dq[i],dq[i+1]);///儲存m+1個(範圍在[0,m])半平面交點 } void Change(int n,double h) ///將所有邊往內縮排h距離 { double dx,dy,len; for(int i=0;i<n;i++) { len=Length(trans[i].s-trans[i].t); dx=(trans[i].s.y-trans[i].t.y)/len*h; dy=(trans[i].t.x-trans[i].s.x)/len*h; L[i].s.x=trans[i].s.x+dx; L[i].s.y=trans[i].s.y+dy; L[i].t.x=trans[i].t.x+dx; L[i].t.y=trans[i].t.y+dy; L[i].angle=trans[i].angle; } } double BSearch(int n) ///二分搜尋 { double l=0,r=20000,mid; int m; while(l+esp<r) { mid=(l+r)/2.0; Change(n,mid); if(Half(n,m)) l=mid; else r=mid; } return l; } int main() { int n,m,t; while(scanf("%d",&n)&&n) { for(int i=0;i<n;++i) scanf("%lf%lf",&poly[i].x,&poly[i].y); poly[n]=poly[0]; for(int i=0;i<n;++i) { trans[i]=LINE(poly[i],poly[i+1]); } printf("%.6f\n",BSearch(n)); } return 0; }