HDOJ 3756(三分)

本文介绍了一种解决三维空间中点集最小覆盖圆锥问题的方法。通过将三维问题转化为二维问题,并利用三分法寻找最优半径及高度,最终实现最小圆锥的确定。

【题目大意】:给出一堆三维的点,求一个最小的圆锥覆盖所有的点。


【解题思路】:下午练习赛的题目啊~~痛痛痛,最后半个小时才发现。。。。

思路是这样子的,首先,圆锥任何一个沿高的截面都是一样的所以,所以对于每一个点都会存在在一个相同的截面上。

基于这里,一个三维的问题其实就可以转化成二维的了。

其次,我们发现,最小的圆锥上至少必有一个点是在所给的点里面,因此,我们不妨可以通过找这个点来达到找圆锥的目的。

很显然的,我们发现,对于一个给定的半径来说,如果存在一个点k在半径与高形成的三角形的斜边上,必存在一个一定的高。

因为体积要求是要最小的,而半径的变化跟体积并无递增关系。故考虑三分极值。

三分半径之后,通过构图可以马上利用相似三角形得到高。。。。


【代码】:

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

using namespace std;

#define eps 1e-6

struct Point
{
    double x, y, z, rr;

    Point() {}
    Point(double a, double b, double c)
    {
        x = a, y = b, z = c, rr = sqrt(x * x + y * y);
    }
} point[20000];

double maxr, ansr, ansh, ansh1;
int n;

double check(double r)
{
    double maxx = -1.0;
    for (int i = 0; i < n; i++)
    {
        double z = point[i].z, rr = point[i].rr;
        double k=point[i].z/(r-point[i].rr);
        if (maxx < k) {maxx = k; }
    }
    return maxx*r;
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d", &n);
        maxr = 0.0;
        double x, y, z;
        for (int i = 0; i < n; i++)
        {
            scanf("%lf%lf%lf", &x, &y, &z);
            point[i] = Point(x, y, z);
            if (point[i].rr > maxr) maxr = point[i].rr;
        }
        double low = maxr, high = 11000, mid, mmid;
        while (low + eps < high)
        {
            mid = (low + high) / 2.0;
            mmid = (mid + high) / 2.0;
            double k1,k2;
            k1=check(mid);
            k2=check(mmid);
            if (k1*mid*mid < k2*mmid*mmid) {
                high = mmid;
                ansr = mid;
                ansh = k1;
            } else {
                low = mid;
                ansr = mmid;
                ansh = k2;
            }
        }
        printf("%.3f %.3f\n", ansh, ansr);
    }
    return 0;
}

【运行结果】:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值