POJ2069 模拟退火算法

POJ2069

Description

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. 


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个点,用一个球体包含这n个点,求最小半径

分析:对于这道题目来说,明显就是要用到概率的方法来做,首先这道题目有一种思想叫做最小圆覆盖,其实感觉也没太多的依附于这种思想,大部分是依据于模拟退火的思想,不断的改变温度t

那么每次找到一个合适的在遍历完一次的时候就更新温度,让其变小范围

这是另外一种解法https://www.cnblogs.com/bennettz/p/8565801.html

下面先上我WA掉的代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int n,m;
int ans;
int a[100];
struct node{
    double x,y,z;
}num[100];
double dis(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(node p){
    double ans=-1;
    rep(i,0,n-1){
    double res=dis(p,num[i]);
    ans=max(ans,res);
    }
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
   while(scanf("%d",&n)!=EOF,n){
        double step=100.0;
        rep(i,0,n-1) scanf("%lf%lf%lf",&num[i].x,&num[i].y,&num[i].z);
        node p=num[0];
        double ans=solve(p);
        while(step>1e-9){
            rep(i,-1,1){
                rep(j,-1,1){
                  rep(l,-1,1){
                    if(i==0&&j==0&&l==0) continue;
                    node q;
                    q.x=p.x+step*i;
                    q.y=p.y+step*j;
                    q.z=p.z+step*l;
                    double res=solve(q);
                    if(res<ans)
                    {
                        ans=res;
                        p=q;
                    }
                  }
                }
            }
            step*=0.99;
        }
//        printf("%.5f %.5f %.5f ",p.x,p.y,p.z);
        printf("%.5f\n",ans);
    }
}

本以为和poj2420差不多,枚举四个方向就好,但是这一道题目,明显将我给WA死了。QAQ

然后就发现另外一种解法,这种解法不管是空间上的还是平面上的最小覆盖圆,都可以使用,最关键的思想就是更新初始点的那个地方

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
int n,m;
int ans;
int a[100];
struct node{
    double x,y,z;
}num[100];
double dis(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));
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
   while(scanf("%d",&n)!=EOF,n){
        double step=100.0;//模拟退火中的温度
        rep(i,0,n-1) scanf("%lf%lf%lf",&num[i].x,&num[i].y,&num[i].z);
        node p=num[0];
        double ans=1000000000;
        while(step>1e-9){
                int k=0;
                rep(i,0,n-1){
                    if(dis(p,num[i])>dis(p,num[k])) k=i;//这个地方算是用到了覆盖圆的思想
                   }
                    double res=dis(p,num[k]);
                    ans=min(ans,res);
                    p.x+=(num[k].x-p.x)/res*step;//这三行,很迷QWQ,这就相当于*一个比(step/res)
                    p.y+=(num[k].y-p.y)/res*step;
                    p.z+=(num[k].z-p.z)/res*step;
            step*=0.99;
        }
        printf("%.5f\n",ans);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值