hdoj 3756 Dome of Circus(三分)

29 篇文章 0 订阅
4 篇文章 0 订阅

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


【解题思路】:这道题上一次做是暑假之后的一次组队赛的题目。其实自从某一次yy到三分极值这种方法之后,顿悟。队友说,一切三分均可秒。

哎...我自惭形秽啊...

首先,圆锥任何一个沿高的截面的形状都是一样的,所以对于每一个点都会在某一个截面上,而截面均相同。

这样,我们完成了首步,某种程度上类似于降维的思想。其次,我们发现截面的一半都是一个直角三角形。

在最小圆锥的这种情况下,必定有至少一个点位于截面三角形的斜边上,而这个点,势必是最外层的点。根据相似三角形的定义,我们可以由直径推出高,或由高推出直径,而且半径越长,高越短,反亦然。

因此,这显然不是一个单调的问题,故而考虑三分极值,因为必定存在一个半径和高满足体积最小这一条件。


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值