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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章