[POJ 2069]Super Star(爬山搜索、最小球覆盖)

题目链接:http://poj.org/problem?id=2069
题目大意:给 n 个点的坐标(xi,yi,zi),求覆盖这 n 个点的最小球的半径r
再一次见识到了模拟退火的威力。首先我们乱定一个圆心,然后退火乱搞就行了,过程比较简单。注意每次移动的变化量参数 delta 最好定为 0.98 ,具体为什么不清楚,但是据网上说设成 0.95 精度就会出现问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <time.h>
#include <cmath>

#define EPS (1e-8)

using namespace std;

struct Point
{
    double x,y,z;
}points[55];

int n,q; //需要被覆盖的点的个数为n,

double dist(Point a,Point 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 getR(Point t) //求圆心为t的最小覆盖球的半径
{
    double tmp=0;
    for(int i=1;i<=n;i++)
        tmp=max(tmp,dist(t,points[i]));
    return tmp;
}

double SA(Point start) //模拟退火,start=最开始确定的圆心
{
    double ans=1e20; //答案=最小覆盖球的半径
    double delta=100; //每次移动的变化量
    while(delta>EPS)
    {
        int d=1; //d为离当前确定的圆心最远的点的编号
        for(int i=1;i<=n;i++)
            if(dist(start,points[i])>dist(start,points[d]))
                d=i;
        double nowr=dist(start,points[d]); //nowr=当前固定圆心的最小覆盖球的半径大小
        ans=min(ans,nowr);
        start.x+=(points[d].x-start.x)/nowr*delta;
        start.y+=(points[d].y-start.y)/nowr*delta;
        start.z+=(points[d].z-start.z)/nowr*delta;
        delta*=0.98;
    }
    return ans;
}

int main()
{
    srand(time(0));
    while(scanf("%d",&n)!=EOF&&n)
    {
        Point center;
        center.x=center.y=center.z=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf",&points[i].x,&points[i].y,&points[i].z);
            center.x+=points[i].x;
            center.y+=points[i].y;
            center.z+=points[i].z;
        }
        center.x=0;
        center.y=0;
        center.z=0;
        /*
        center.x/=n;
        center.y/=n;
        center.z/=n;*/
        printf("%.5lf\n",SA(center));
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值