欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算几何(空间几何 + 三分) - Dome of Circus - UVA 1473

程序员文章站 2022-07-13 13:52:44
...

计算几何(空间几何 + 三分) - Dome of Circus - UVA 1473

题意:

空 间 中 给 出 n 个 点 , 要 求 用 一 个 底 面 在 x O y 平 面 , 顶 点 在 z 轴 正 半 轴 的 圆 锥 包 含 这 n 个 点 。 空间中给出n个点,要求用一个底面在xOy平面,顶点在z轴正半轴的圆锥包含这n个点。 nxOyzn

要 求 这 圆 锥 的 体 积 最 小 , 计 算 此 时 圆 锥 的 底 面 半 径 和 高 。 要求这圆锥的体积最小,计算此时圆锥的底面半径和高。

输入:

多 组 测 试 数 据 , 多组测试数据,

每 组 首 行 包 括 一 个 正 整 数 n , 表 示 点 的 个 数 , 每组首行包括一个正整数n,表示点的个数, n

接 着 n 行 每 行 包 括 3 个 浮 点 数 x , y , z , 表 示 点 的 坐 标 。 接着n行每行包括3个浮点数x,y,z,表示点的坐标。 n3x,y,z

输出:

两 个 浮 点 数 , 分 别 表 示 圆 锥 的 高 和 底 面 半 径 。 两个浮点数,分别表示圆锥的高和底面半径。

小 数 点 后 保 留 三 位 。 小数点后保留三位。

Sample Input

1
1.00 0.00 1.00
2
1.00 0.00 1.00
0.00 1.50 0.50
3
1.00 0.00 1.00
0.00 1.50 0.50
-0.50 -0.50 1.00

Sample Output

3.000 1.500
2.000 2.000
2.000 2.000

数据范围:

1 ≤ n ≤ 10000 1 ≤ n ≤ 10000 1n10000


分析:

不 难 发 现 , 半 径 越 大 、 高 越 大 , 就 越 容 易 包 含 所 有 点 。 不难发现,半径越大、高越大,就越容易包含所有点。

圆 锥 的 体 积 应 当 满 足 一 个 单 峰 的 凹 函 数 , 故 我 们 考 虑 用 三 分 法 来 求 这 个 最 小 值 。 圆锥的体积应当满足一个单峰的凹函数,故我们考虑用三分法来求这个最小值。

我 们 三 分 半 径 , 对 于 每 次 三 分 得 到 的 两 个 半 径 r 1 和 r 2 , 我们三分半径,对于每次三分得到的两个半径r_1和r_2, r1r2

我 们 通 过 比 例 关 系 计 算 出 , 每 个 半 径 对 应 的 , 能 够 覆 盖 所 有 点 的 圆 锥 的 高 h 1 和 h 2 , 如 下 图 我们通过比例关系计算出,每个半径对应的,能够覆盖所有点的圆锥的高h_1和h_2,如下图 h1h2

计算几何(空间几何 + 三分) - Dome of Circus - UVA 1473
对 于 每 一 个 点 P ( x , y , z ) , 利 用 相 似 三 角 形 的 性 质 , 有 如 下 等 式 : 对于每一个点P(x,y,z),利用相似三角形的性质,有如下等式: P(x,y,z)

x 2 + y 2 r = h − z h \frac{\sqrt{x^2+y^2}}{r}=\frac{h-z}{h} rx2+y2 =hhz

解 得 : 解得:

h = z ⋅ r r − x 2 + y 2 h=\frac{z·r}{r-\sqrt{x^2+y^2}} h=rx2+y2 zr

那 么 h = m a x i = 1 n { z i ⋅ r r − x i 2 + y i 2 } 那么h=max_{i=1}^n\{\frac{z_i·r}{r-\sqrt{x_i^2+y_i^2}}\} h=maxi=1n{rxi2+yi2 zir}

最 后 三 分 输 出 极 值 点 处 的 底 面 半 径 和 高 即 可 。 最后三分输出极值点处的底面半径和高即可。

代码:

#include<cstring>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>

using namespace std;

const double eps=1e-10;
const double pi=cos(-1.0);

int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    else return x<0 ? -1 : 1;
}

struct Point3
{
    double x,y,z;
    Point3(double x=0,double y=0,double z=0) : x(x), y(y), z(z) {}
    bool operator < (const Point3 &t) const
    {
        return z<t.z;
    }
};

int n;
Point3 V[10010];

double check(double r)
{
    double h=0;
    for(int i=0;i<n;i++)
    {
        double d=sqrt(V[i].x*V[i].x+V[i].y*V[i].y);
        h=max(h,V[i].z/(r-d)*r);
    }
    return h;
}

int main()
{
    while(~scanf("%d",&n))
    {
        double L=0,R=1e20;
        for(int i=0;i<n;i++) scanf("%lf%lf%lf",&V[i].x,&V[i].y,&V[i].z);

        while(R-L>eps)
        {
            double lmid=(L+R)/2, rmid=(lmid+R)/2;
            double h1=check(lmid), h2=check(rmid);
            double v1=1.0/3.0*pi*lmid*lmid*h1, v2=1.0/3.0*pi*rmid*rmid*h2;
            if(v1>v2) L=lmid;
            else R=rmid;
        }
        
        printf("%.3lf %.3lf\n",check(L),L);
    }
    return 0;
}