BZOJ4885: [Lydsy2017年5月月赛]长方体

时间:2021-04-07 19:21:39

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4885

Description

给定一个a*b*c的长方体,定义其表面上两个点的距离为沿着长方体的表面走的最短路径的长度,请找到距离最远的点对。

Input

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

Output

输出一行一个实数,即最远点对的距离,与标准答案的绝对或相对误差不超过10^{-8}时会被认为是正确的。

Sample Input

1 1 1

Sample Output

2.2360679774998

HINT

 你需要保证找到的两个点里至少有一个是长方体顶点

题解:

最远点对必然包含至少一个顶点。枚举一个顶点,然后枚举一个面,在那个面上三分套三分即可。

//枚举顶点和一个面,然后三分套三分
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
double ans,r;
const double eps=1e-8;
double LL,WW,HH;
struct P{
  double x,y,z;
  P(){}
  P(double _x,double _y,double _z){x=_x,y=_y,z=_z;}
}a[8];
void turn(int i,int j,double x,double y,double z,double x0,double y0,double L,double W,double H){
  if(z==0){
    double R=x*x+y*y;
    if(R<r)r=R;
  }else{
    if(i>=0&&i<2)turn(i+1,j,x0+L+z,y,x0+L-x,x0+L,y0,H,W,L);
    if(j>=0&&j<2)turn(i,j+1,x,y0+W+z,y0+W-y,x0,y0+W,L,H,W);
    if(i<=0&&i>-2)turn(i-1,j,x0-z,y,x-x0,x0-H,y0,H,W,L);
    if(j<=0&&j>-2)turn(i,j-1,x,y0-z,y-y0,x0,y0-H,L,H,W);
  }
}
double cal(double x1,double y1,double z1,double x2,double y2,double z2){
  double L=LL,W=WW,H=HH;
  if(fabs(z1)>eps&&fabs(z1-H)>eps)if(fabs(y1)<eps||fabs(y1-W)<eps)
    swap(y1,z1),swap(y2,z2),swap(W,H);
  else
    swap(x1,z1),swap(x2,z2),swap(L,H);
  if(fabs(z1-H)<eps)z1=0,z2=H-z2;
  r=1e20;
  turn(0,0,x2-x1,y2-y1,z2,-x1,-y1,L,W,H);
  return r;
}
double solvexy(double x,double y,double z,double A,double B,double C){
  double l=0,r=C,m1,m2,s1,s2;
  double ret=0;
  while(l+eps<r){
    double len=(r-l)/3.0;
    m1=l+len;
    m2=r-len;
    s1=cal(x,y,z,A,B,m1);
    s2=cal(x,y,z,A,B,m2);
    ret=max(ret,max(s1,s2));
    if(s1>s2)r=m2;else l=m1;
  }
  return ret;
}
double solvexz(double x,double y,double z,double A,double B,double C){
  double l=0,r=B,m1,m2,s1,s2;
  double ret=0;
  while(l+eps<r){
    double len=(r-l)/3.0;
    m1=l+len;
    m2=r-len;
    s1=cal(x,y,z,A,m1,C);
    s2=cal(x,y,z,A,m2,C);
    ret=max(ret,max(s1,s2));
    if(s1>s2)r=m2;else l=m1;
  }
  return ret;
}
double solvex(double x,double y,double z,double A,double B,double C){
  double l=0,r=B,m1,m2,s1,s2;
  double ret=0;
  while(l+eps<r){
    double len=(r-l)/3.0;
    m1=l+len;
    m2=r-len;
    s1=solvexy(x,y,z,A,m1,C);
    s2=solvexy(x,y,z,A,m2,C);
    ret=max(ret,max(s1,s2));
    if(s1>s2)r=m2;else l=m1;
  }
  return ret;
}
double solvey(double x,double y,double z,double A,double B,double C){
  double l=0,r=A,m1,m2,s1,s2;
  double ret=0;
  while(l+eps<r){
    double len=(r-l)/3.0;
    m1=l+len;
    m2=r-len;
    s1=solvexy(x,y,z,m1,B,C);
    s2=solvexy(x,y,z,m2,B,C);
    ret=max(ret,max(s1,s2));
    if(s1>s2)r=m2;else l=m1;
  }
  return ret;
}
double solvez(double x,double y,double z,double A,double B,double C){
  double l=0,r=A,m1,m2,s1,s2;
  double ret=0;
  while(l+eps<r){
    double len=(r-l)/3.0;
    m1=l+len;
    m2=r-len;
    s1=solvexz(x,y,z,m1,B,C);
    s2=solvexz(x,y,z,m2,B,C);
    ret=max(ret,max(s1,s2));
    if(s1>s2)r=m2;else l=m1;
  }
  return ret;
}
int main(){
  int i,j;
  double L,H,W;
  scanf("%lf%lf%lf",&L,&W,&H);
  a[0]=P(0,0,0);
  a[1]=P(0,0,H);
  a[2]=P(0,W,0);
  a[3]=P(0,W,H);
  a[4]=P(L,0,0);
  a[5]=P(L,0,H);
  a[6]=P(L,W,0);
  a[7]=P(L,W,H);
  LL=L;
  WW=W;
  HH=H;
  for(i=0;i<8;i++)for(j=0;j<8;j++)
    ans=max(ans,cal(a[i].x,a[i].y,a[i].z,a[j].x,a[j].y,a[j].z));
  for(i=0;i<8;i++){
    ans=max(ans,solvex(a[i].x,a[i].y,a[i].z,0,W,H));
    ans=max(ans,solvex(a[i].x,a[i].y,a[i].z,L,W,H));
    ans=max(ans,solvey(a[i].x,a[i].y,a[i].z,L,0,H));
    ans=max(ans,solvey(a[i].x,a[i].y,a[i].z,L,W,H));
    ans=max(ans,solvez(a[i].x,a[i].y,a[i].z,L,W,0));
    ans=max(ans,solvez(a[i].x,a[i].y,a[i].z,L,W,H));
  }
  double ret=sqrt(ans);
  printf("%.13f",ret);
  return 0;
}