C-Super Star (POJ-2069)(最小球覆盖+模拟退火)

During a voyage of the starship Hakodate-maru (see Problem 1406), researchers found strange synchronized movements of stars. Having heard these observations, Dr. Extreme proposed a theory of "super stars". Do not take this term as a description of actors or singers. It is a revolutionary theory in astronomy.
According to this theory, starts we are observing are not independent objects, but only small portions of larger objects called super stars. A super star is filled with invisible (or transparent) material, and only a number of points inside or on its surface shine. These points are observed as stars by us.

In order to verify this theory, Dr. Extreme wants to build motion equations of super stars and to compare the solutions of these equations with observed movements of stars. As the first step, he assumes that a super star is sphere-shaped, and has the smallest possible radius such that the sphere contains all given stars in or on it. This assumption makes it possible to estimate the volume of a super star, and thus its mass (the density of the invisible material is known).

You are asked to help Dr. Extreme by writing a program which, given the locations of a number of stars, finds the smallest sphere containing all of them in or on it. In this computation, you should ignore the sizes of stars. In other words, a star should be regarded as a point. You may assume the universe is a Euclidean space.

Input

The input consists of multiple data sets. Each data set is given in the following format.

n
x1 y1 z1
x2 y2 z2
. . .
xn yn zn

The first line of a data set contains an integer n, which is the number of points. It satisfies the condition 4 <= n <= 30.

The location of n points are given by three-dimensional orthogonal coordinates: (xi, yi, zi) (i = 1, ..., n). Three coordinates of a point appear in a line, separated by a space character. Each value is given by a decimal fraction, and is between 0.0 and 100.0 (both ends inclusive). Points are at least 0.01 distant from each other.

The end of the input is indicated by a line containing a zero.

Output

For each data set, the radius of the smallest sphere containing all given points should be printed, each in a separate line. The printed values should have 5 digits after the decimal point. They may not have an error greater than 0.00001.

Sample Input

4
10.00000 10.00000 10.00000
20.00000 10.00000 10.00000
20.00000 20.00000 10.00000
10.00000 20.00000 10.00000
4
10.00000 10.00000 10.00000
10.00000 50.00000 50.00000
50.00000 10.00000 50.00000
50.00000 50.00000 10.00000
0

Sample Output

7.07107
34.64102

 

在昨天晚上的比赛中的这道题,是一道最小球覆盖+模拟退火的题,由于我正在做数学专题里的题,在做数学专题之前,因为数学专题里的题很多,所以我就搜了搜每个题用到的算法,一类算法的题一起做,所以就对这道题很有印象。但是还没有做到,就很难受。

题意:给你n个点,让你求覆盖这些点的最小球半径。

思路:这道题的话,我在刚才看了看最小圆覆盖和模拟退火的一些知识,然后这道题是最小球覆盖,当我们把每一个球看成一个点的时候,其实和最小圆覆盖也差不太多。

关于模拟退火:https://blog.csdn.net/weixin_43846139/article/details/105594911

求最小球覆盖的步骤:

 (1)对于一个点:球心就是这个点,且半径无穷小。
 (2)对于两个点:球心就是两点线段的中点,半径就是线段长度的一半。
 (3)对于三个点:三点构成的平面必为球的大圆,球心是三角形的外心,半径就是球心到某个点的距离。
 (4)对于四个点:若四点共面,则转换到3点共面;若四点不共面,四面体可以唯一确定一个外接球。
 (5)对于五个及以上的点:最小球必为某四个点的外接球。


有了具体步骤,根据上述推导过程我们可以知道最小球覆盖的球心一定与他距离最远的点有且最多有4个等距离的点。那么我们可以先假设一个点为球心,找到与他距离最远的点,并移动球心靠近该点,不断重复此过程,就能找到最小球覆盖的球心了。

PS:果然如lly大佬所说,就是一个模拟退火的sb题,完全就是个板子。

AC代码:

#include <stdio.h>
#include <string>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int maxx=1010;
const int mod=10007;
const int inf=0x3f3f3f3f;
const double eps=1e-5;
using namespace std;
struct node
{
    double x,y,z;
} p[maxx],op;
int n;
double dist(node &a,node &b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
double solve()
{
    double ret,delta=100.0;
    double maxDis,tempDis;
    int i,id;
    while(delta>eps)
    {
        id=0;
        maxDis=dist(op,p[id]);
        for(i=1; i<n; i++)
        {
            tempDis=dist(op,p[i]);
            if(tempDis>maxDis)
            {
                maxDis=tempDis;
                id=i;
            }
        }
        ret=maxDis;
        op.x+=(p[id].x-op.x)/maxDis*delta;
        op.y+=(p[id].y-op.y)/maxDis*delta;
        op.z+=(p[id].z-op.z)/maxDis*delta;
        delta*=0.98;
    }
    return ret;
}
int main()
{
    while(~scanf("%d",&n),n)
    {
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
        }
        printf("%.5f\n", solve());
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值