【题目大意】:给出一堆三维的点,求一个最小的圆锥覆盖所有的点。
【解题思路】:下午练习赛的题目啊~~痛痛痛,最后半个小时才发现。。。。
思路是这样子的,首先,圆锥任何一个沿高的截面都是一样的所以,所以对于每一个点都会存在在一个相同的截面上。
基于这里,一个三维的问题其实就可以转化成二维的了。
其次,我们发现,最小的圆锥上至少必有一个点是在所给的点里面,因此,我们不妨可以通过找这个点来达到找圆锥的目的。
很显然的,我们发现,对于一个给定的半径来说,如果存在一个点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;
}
【运行结果】:

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

1298

被折叠的 条评论
为什么被折叠?



