题意:
给(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;
}