三分套三分(bzoj4885)

本文介绍了一种求解长方体内任意两点间最大距离的算法,通过枚举顶点并采用三分法搜索最优解。适用于计算几何问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般上大家都会想到与所选点对立的那个顶点就是最远,这明显是错误的,举个例子:a=100,b=1,c=1;答案应该是100.50626871

首先长方体每个顶点等价,枚举任意一个点就好。

其次一个点最远的距离显然是在3个与其不相邻的面取到的。

所以这时候需要枚举其这三个面上所有的点进行比较。由于面上点没有单调性,所以不能二分,要三分。。。

具体怎么做呢?首先枚举三个面,每个面先枚举长,在枚举宽,然后算一下长度,在进行比较,轻松出解

#include<bits/stdc++.h>
using namespace std;
double l,w,h;
double f(double a,double b,double c){return (a+b)*(a+b)+c*c;}
double ff(double a){return a*a;}
double solve(double a,double b,double c)//比较点到该面上的长度
{
    double ans=1e20;
    if(a!=l)ans=min(ans,f(c,b,a));
    else if(a==l)ans=min(ans,min(ff(w+c)+ff(l+w-b),ff(h+b)+ff(l+h-c)));
    if(b!=w) ans=min(ans,f(a,c,b));
    else if(b==w)ans=min(ans,min(ff(l+c)+ff(l+w-a),ff(h+a)+ff(w+h-c)));
    if(c!=h) ans=min(ans,f(a,b,c));
    else if(c==h)ans=min(ans,min(ff(w+a)+ff(h+w-b),ff(l+b)+ff(l+h-a)));
    return ans;
}
double solvexy(double a,double b,double c)
{
    double l=0,r=c,ans=0;int t=100;
    while(t--)
    {
        double m1=(l*2+r)/3;
        double m2=(l+2*r)/3;
        double tmp1=solve(a,b,m1);
        double tmp2=solve(a,b,m2);
        ans=max(ans,max(tmp1,tmp2));
        if(tmp1>tmp2)r=m2;else l=m1;
    }return ans;
}
double solvexz(double a,double b,double c)
{
    double l=0,r=b,ans=0;int t=100;
    while(t--)
    {
        double m1=(l*2+r)/3;
        double m2=(l+2*r)/3;
        double tmp1=solve(a,m1,c);
        double tmp2=solve(a,m2,c);
        ans=max(ans,max(tmp1,tmp2));
        if(tmp1>tmp2)r=m2;else l=m1;
    }return ans;
}
double solvex(double a,double b,double c)//枚举yz面
{
    double l=0,r=b,ans=0;int t=100;
    while(t--)
    {
        double m1=(l*2+r)/3;
        double m2=(l+2*r)/3;
        double tmp1=solvexy(a,m1,c);
        double tmp2=solvexy(a,m2,c);
        ans=max(ans,max(tmp1,tmp2));
        if(tmp1>tmp2)r=m2;else l=m1;
    }return ans;
}
double solvey(double a,double b,double c)//枚举xz面
{
    double l=0,r=a,ans=0;int t=100;
    while(t--)
    {
        double m1=(l*2+r)/3;
        double m2=(l+r*2)/3;
        double tmp1=solvexy(m1,b,c);
        double tmp2=solvexy(m2,b,c);
        ans=max(ans,max(tmp1,tmp2));
        if(tmp1>tmp2)r=m2;else l=m1;
    }return ans;
}
double solvez(double a,double b,double c)//枚举xy面
{
    double l=0,r=a,ans=0;int t=100;
    while(t--)
    {
        double m1=(l*2+r)/3;
        double m2=(l+r*2)/3;
        double tmp1=solvexz(m1,b,c);
        double tmp2=solvexz(m2,b,c);
        ans=max(ans,max(tmp1,tmp2));
        if(tmp1>tmp2)r=m2;else l=m1;
    }return ans;
}
int main()
{
    double ans;scanf("%lf%lf%lf",&l,&w,&h);
    ans=min(f(l,w,h),min(f(l,h,w),f(h,w,l)));
    ans=max(ans,solvex(l,w,h));
    ans=max(ans,solvey(l,w,h));
    ans=max(ans,solvez(l,w,h));
    printf("%.8lf\n",sqrt(ans));return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值