D - Country Meow

Country Meow - Gym 101981D - Virtual Judge (vjudge.net)
题意:

给定三维坐标中的n个点,求一个点使得其到最远点的距离最小。

以这个点为圆心,这个点到最远点的距离为半径的球就是最小的能够覆盖所有点集的球。也就是找最小覆盖球。

做法:

考虑一种逼近算法,我们想要从原点坐标p开始逼近,逼近到我们想要的圆心坐标。可以这样操作:
每次找到距离p点的最远点,设p点到当前最远点的距离为len,更新p点,让p点走len的一部分长度逼近当前最远点,然后让这个部分越来越小,比如第一次走len的三分之二,第二次走len的三分之一。降为到二维平面模拟一下过程如下:

我们从黑点(坐标原点)开始逼近,
第一次逼近:最远点是1,走一部分长度。
第二次逼近:最远点是3,走一小部分长度。
第三次逼近:最远点是2,走更小一部分长度。

如此逼近下去,我们就能逼近到我们想要的圆心坐标:

附上代码:
 

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e3 + 10;
struct node
{
    double x, y, z;
} point[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));
}
void solve()
{

    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> point[i].x >> point[i].y >> point[i].z;
    double step = 100;     // 每次走的步数大小的指标
    double rate = 0.99999; // 每次走的步数大小的减小指标
    double eps = 1e-3;     // 精度
    node p = {0, 0, 0};    // 从原点坐标开始逼近
    double ans = 1e9;      // 每次找到距离p点的最远点,一直取最小值
    int idx = 0;           // 上一个距离p点的最远点
    while (step > eps)
    {
        for (int i = 1; i <= n; i++)
        {
            if (dist(p, point[i]) > dist(p, point[idx])) // 找到当前距离p点最远的点
                idx = i;
        }
        double len = dist(p, point[idx]); // 距离p点最远的点的长度
        ans = min(ans, len);
        p.x += (point[idx].x - p.x) * (step / len);
        p.y += (point[idx].y - p.y) * (step / len);
        p.z += (point[idx].z - p.z) * (step / len);
        // 走的步长是p点距离当前最远点的一部分
        step *= rate;
        // step逐渐减小,每次走的步长从p点距离当前最远点的一部分逐渐变成一小部分
    }
    cout << ans << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    // cin >> t;
    t = 1;
    while (t--)
        solve();
}

其实这种算法叫做模拟退火算法,有关模拟退火算法:模拟退火算法_模拟退火算法路径规划的缺点-CSDN博客

这里的step相当于初始温度,rate相当于降温速率,eps相当于温度下限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值