POJ - 2069 Super Star & HDU - 3007 Buried memory

模拟退火求最小球覆盖和最小圆覆盖

原本在我的认识中,模拟退火一定要有一个随机化在里面。

但是有些模拟退火,你可以清楚地意识到答案是可以向某个方向逼近的,这个时候就不用随机了。

比如像第一道题POJ 2069,这道题求的就是最小球覆盖。

对于任意的初始点,我们都能算出以当前点作为圆心的覆盖半径是多少。

显然,决定这条半径多长的,是所有点中离圆心最远的。

那么我们是不是可以越来越靠近这个最远的点,使得最远的距离最小,也就是球的半径能最小?

答案是肯定的,我们直接慢慢地更新答案即可。

同时我们也套上模拟退火的板子,用一个T来表示那一步移动的步长。

最小圆覆盖当然比三维情况要简单,所以能理解上面的,那道题也就顺便切掉了。

分别附上这两道题的代码:

POJ 2069

#include<cstdio>
#include<cmath>
const int maxn = 35;
const double delta = 0.98;
struct Point
{
    double x, y, z;
} s[maxn];
double ansx, ansy, ansz, ans;
int n;

inline double sq(double x)
{
     return x * x;
}
double dist(double x, double y, double z, double xx, double yy, double zz)
{
    return sqrt(sq(x - xx) + sq(y - yy) + sq(z - zz));
}

int main()
{
    while(scanf("%d", &n) == 1 && n)
    {
        ansx = ansy = ansz = 0;// 取平均值过不了是最骚的
        for(int i = 1; i <= n; i++)
        {
            scanf("%lf%lf%lf", &s[i].x, &s[i].y, &s[i].z);
        }
        for(double T = 100; T > 1e-15; T = T * delta)// 话说这道题卡精度
        {
            double maxdist = -1e15; int idx = -1;
            for(int i = 1; i <= n; i++)
            {
                double temp = dist(ansx, ansy, ansz, s[i].x, s[i].y, s[i].z);
                if(temp > maxdist)
                {
                    maxdist = temp; idx = i;
                }
            }
            ans = maxdist;
            ansx += (s[idx].x - ansx) / maxdist * T;
            ansy += (s[idx].y - ansy) / maxdist * T;
            ansz += (s[idx].z - ansz) / maxdist * T;
        }
        printf("%.5lf\n", ans);
    }
    return 0;
}

HDU 3007

#include<cstdio>
#include<cmath>
const int maxn = 505;
struct Nodes
{
    double x, y;
} s[maxn];
double ansx, ansy;
int n;
inline double sq(double x)
{
    return x * x;
}
double dist(double x, double y, double xx, double yy)
{
    return sqrt(sq(x - xx) + sq(y - yy));
}
int main()
{
    while(scanf("%d", &n) == 1 && n)
    {
        ansx = ansy = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%lf%lf", &s[i].x, &s[i].y);
            ansx += s[i].x; ansy += s[i].y;
        }
        ansx /= n; ansy /= n;
        const double delta = 0.98;
        for(double T = 2018; T > 1e-10; T *= delta)
        {
            double maxr = -1e10; int idx = -1;
            for(int i = 1; i <= n; i++)
            {
                double temp = dist(ansx, ansy, s[i].x, s[i].y);
                if(temp > maxr)
                {
                    maxr = temp; idx = i;
                }
            }
            ansx += (s[idx].x - ansx) / maxr * T;
            ansy += (s[idx].y - ansy) / maxr * T;
        }
        printf("%.2lf %.2lf %.2lf\n", ansx, ansy, dist(ansx, ansy, s[1].x, s[1].y));
    }
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/9913287.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值