最小球覆盖:用半径最小的球去覆盖所有点。
纯粹的退火算法,是搞不定的,精度不够,不然就会TLE,根本跑不出答案来。
任取一点为球心,然后一点点靠近最远点。其实这才是最主要的。
因为:4个点确定一个球,也就是说,这个球,会慢慢稳定,每次用一个点到最远的点的距离去靠近,怎么靠近,玄学距离 。
再在这个基础上乘以 t ,模拟退火温度。这样靠近速度增加。并且不用判断是否较以前是否更优才转移,因为他是必须转移过去。至少你不可能是最长边的端点的,而且他会随着温度逐渐稳定。
#include <stdio.h> #include <math.h> #include <algorithm> using namespace std; const int maxn = 35; struct Node { double x,y,z; }nodes[maxn]; int 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) ); } double calc(Node z) { double ret = 0; for(int i = 0; i < n; i++) ret = max(ret,dist(z,nodes[i])); return ret; } int dx[6] = {0,0,0,0,1,-1}; int dy[6] = {0,0,-1,1,0,0}; int dz[6] = {-1,1,0,0,0,0}; int main() { //freopen("in.txt","r",stdin); while(scanf("%d",&n),n) { for(int i = 0; i < n; i++) scanf("%lf%lf%lf",&nodes[i].x,&nodes[i].y,&nodes[i].z); Node s = nodes[0]; double t = 10; double ans = 0x3f3f3f3f; while(t>1e-8) { double d = 0; int k = 0; for(int i = 0; i < n; i++) { double dis = dist(s,nodes[i]); if(d<dis) { d = dis; k = i; } } Node z; z.x = s.x + (nodes[k].x-s.x)/d*t; z.y = s.y + (nodes[k].y-s.y)/d*t; z.z = s.z + (nodes[k].z-s.z)/d*t; ans = min(ans,d); s = z; t = t*0.98; } printf("%.5f ",ans); } return 0; }