1. 程式人生 > >poj 3384 Feng Shui (半平面交求可以放入的兩個相同圓的最大面積)

poj 3384 Feng Shui (半平面交求可以放入的兩個相同圓的最大面積)

題目連結: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
*/