Gym

题意:

(n)个三维点,问最小覆盖球的半径。

思路:

模拟退火。

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<bitset>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 10;
const ll INF = 1e18;
const ll MOD = 1e9 + 7;

const double t0 = 0.995;
const double eps = 1e-14;
double ansx, ansy, ansz, ans;
struct Point{
    double x, y, z;
}p[maxn];
int n;
double solve(double x, double y, double z){
    double ret = 0;
    for(int i = 1; i <= n; i++){
        ret = max(sqrt((p[i].x - x) * (p[i].x - x) + (p[i].y - y) * (p[i].y - y) + (p[i].z - z) * (p[i].z - z)), ret);
    }
    return ret;
}
void sa(){
    double t = 2000;
    double X = ansx, Y = ansy, Z = ansz;
    while(t > eps){
        double x = X + (rand() * 2 - RAND_MAX) * t;
        double y = Y + (rand() * 2 - RAND_MAX) * t;
        double z = Z + (rand() * 2 - RAND_MAX) * t;
        double now = solve(x, y, z);
        double del = now - ans;
        if(del < 0){
            X = x, Y = y, Z = z;
            ansx = x, ansy = y, ansz = z;
            ans = now;
        }
        else if(exp(-del / t) * RAND_MAX > rand()){
            X = x, Y = y, Z = z;
        }
        t *= t0;
    }
}
char s[maxn];
int main(){
    srand(131313131);
    srand(rand());
    scanf("%d", &n);
    double x = 0, y = 0, z = 0;
    for(int i = 1; i <= n; i++){
        scanf("%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z);
        x += p[i].x, y += p[i].y, z += p[i].z;
    }
    ansx = x / n, ansy = y / n, ansz = z / n; //平均数
    ans = 1e18;
    for(int i = 1; i <= 10; i++) sa();
    printf("%.10f
", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/KirinSB/p/11676149.html