poj 3384 Feng Shui (半平面交求可以放入的兩個相同圓的最大面積)
阿新 • • 發佈:2018-11-25
題目連結:poj 3384
題意:順時針給n個點,給你兩個半徑相等的圓,將兩個半徑為 r 的圓放入一個多邊形中,兩圓可以重疊,問兩個圓佔據最大面積時圓心座標是多少?
題解:我們先求出凸多邊形每條邊內縮r之後的核,那麼這兩圓的圓心座標肯定在這核裡面,這時我們就列舉核頂點,找出最遠距離的兩個頂點作為兩個圓心座標,因為兩圓心相離越遠,它們兩個佔用的面積就越大。
這題我真的想開罵了,一直Output Limit Exceeded 和 wa ,之後把叉積判斷那裡>0的改成>esp,就過了。艹。
以後凡是遇到0的,全用esp代替。
///半平面交 #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int maxn=110; 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; } void 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; dq[++r]=dq[l];///將頭向量加到尾部 for(int i=l;i<r;++i) poly[m++]=Getlinenode(dq[i],dq[i+1]);///儲存m+1個(範圍在[0,m])半平面交點 } double h; void Change(int n) ///將所有邊往內縮排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)*h/len; dy=(trans[i].t.x-trans[i].s.x)*h/len; 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; } } void solve(int n) { int m; Change(n); Half(n,m); point r1,r2; double dis=-999; for(int i=0;i<m;i++) { // printf("%f %f\n",poly[i].x,poly[i].y); for(int j=0;j<m;j++) { if(dcmp(dis-Length(poly[i]-poly[j]))<0){ dis=Length(poly[i]-poly[j]); r1=poly[i];r2=poly[j]; } } } printf("%.4f %.4f %.4f %.4f\n",r1.x+esp,r1.y+esp,r2.x+esp,r2.y+esp); } int main() { int n,m,t; while(~scanf("%d%lf",&n,&h)) { 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+1],poly[i]); } solve(n); } return 0; } /* 5 2 -2 0 -5 3 0 8 7 3 5 0 -2.171573 3.000000 -1.171573 2.000000 3.929632 2.000000 4.261709 2.498115 0.216195 5.387768 -2.1716 3.0000 4.2617 2.4981 4 3 0 0 0 8 10 8 10 0 3.000000 3.000000 7.000000 3.000000 7.000000 5.000000 3.000000 5.000000 3.0000 3.0000 7.0000 5.0000 */