bzoj 4885: [Lydsy2017年5月月赛]长方体

Description

给定一个a*b*c的长方体,定义其表面上两个点的距离为沿着长方体的表面走的最短路径的长度,请找到距离最远的点对,你需要保证找到的两个点里至少有一个是长方体顶点。

Input

第一行包含三个正整数a,b,c(1<=a,b,c<=1000),即长方体的长、宽、高。

Output

输出一行一个实数,即最远点对的距离,与标准答案的绝对或相对误差不超过10^{-8}时会被认为是正确的。
 
首先长方体的八个顶点等价,所以可以任选一个考虑
显然最远点会在和所选顶点不相邻的三个面中的某一个上
枚举这三个面,画出展开图,
设当前面的长宽为a,b,长方体的长宽高为a,b,c,所选顶点与这个面不相邻
建直角系,使展开图中当前面在0<x<a,0<y<b区域
所选顶点在展开图中有意义的位置可以是(0,-c),(-c,0),(a+c,-a),(-b,b+c)之一
二分答案,问题转化为以这四个点为圆心,答案为半径的圆是否覆盖了整个矩形,这是计算几何的经典问题,可以考虑几种情况:
1.一个圆与矩形无交,可以忽略这个圆
2.一个圆包含了矩形,可以直接判定整个矩形被覆盖
3.否则 整个矩形没有被覆盖 当且仅当 存在一个圆,这个圆上存在一个点满足在矩形内且在其余圆外,可以求出圆之间、圆和矩形的交点判断一下
最后对三个面的答案取max
#include<bits/stdc++.h>
typedef double ld;
ld ans=0;
void maxs(ld&a,ld b){if(a<b)a=b;}
const ld _0=1e-18;
int T,n;
ld xm,ym,x[5],y[5],r[5];
ld dis2(ld x,ld y){return x*x+y*y;}
ld dis(ld x,ld y){return sqrt(x*x+y*y);}
bool out(int w){
    return x[w]+r[w]<0||x[w]-r[w]>xm||y[w]+r[w]<0||y[w]-r[w]>ym;
}
bool in(int w){
    ld r2=r[w]*r[w];
    return dis2(x[w],y[w])<r2&&dis2(x[w]-xm,y[w])<r2&&
    dis2(x[w],y[w]-ym)<r2&&dis2(x[w]-xm,y[w]-ym)<r2;
}
struct ev{
    ld x;
    int a;
    bool operator<(ev w)const{return x<w.x;}
}es[107];
const ld pi=acos(-1),_2pi=pi*2;
ld fix(ld x){
    while(x<0)x+=_2pi;
    while(x>=_2pi)x-=_2pi;
    return x;
}
int s,ep;
void cal(ld a,ld b){
    ld l=fix(a-b),r=fix(a+b);
    if(l>r)++s;
    es[ep++]=(ev){l-_0,1};
    es[ep++]=(ev){r+_0,-1};
}
void f(ld a,ld b,ld c){
    xm=a,ym=b;
    x[0]=-c,y[0]=0;
    x[1]=0,y[1]=-c;
    x[2]=a+c,y[2]=-a;
    x[3]=-b,y[3]=b+c;
    ld L=0,R=a+b+c,M;
    while(R-L>1e-10){
        M=(L+R)/2;
        for(int i=0;i<4;++i)r[i]=M;
        bool ed=1,ed0=0;
        for(int i=0;i<4;++i){
            if(out(i))continue;
            ed0=1;
            if(in(i))break;
            s=0,ep=0;
            for(int j=0;j<4;++j)if(j!=i){
                ld xd=x[j]-x[i],yd=y[j]-y[i];
                ld d=dis(xd,yd);
                if(r[j]+r[i]<d+_0)continue;
                ld a=atan2(yd,xd),b=acos(d/(2*r[i]));
                cal(a,b);
            }
            if(x[i]-r[i]<0)cal(pi,acos(x[i]/r[i]));
            if(x[i]+r[i]>xm)cal(0,acos((xm-x[i])/r[i]));
            if(y[i]-r[i]<0)cal(pi*1.5,acos(y[i]/r[i]));
            if(y[i]+r[i]>ym)cal(pi*0.5,acos((ym-y[i])/r[i]));
            if(!ep){ed=0;goto o;}
            std::sort(es,es+ep);
            for(int j=0;j<ep;++j)if(!(s+=es[j].a)){ed=0;goto o;}
            oo:;
        }
        if(!ed0)ed=0;
        o:;
        if(ed)R=M;
        else L=M;
    }
    maxs(ans,L);
}
int main(){
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    f(a,b,c);f(b,c,a);f(c,a,b);
    printf("%.10f",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/6828641.html