poj 3384 Feng Shui (半平面交求可以放入的两个相同圆的最大面积)

版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/84330763

题目链接: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
*/

猜你喜欢

转载自blog.csdn.net/LJD201724114126/article/details/84330763
今日推荐