//目录

POJ 最小球覆盖 模拟退火

最小球覆盖:用半径最小的球去覆盖所有点。

纯粹的退火算法,是搞不定的,精度不够,不然就会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\n",ans);
​
    }
​
    return 0;
}

 


 

 

posted @ 2018-01-31 14:51  小草的大树梦  阅读(386)  评论(0编辑  收藏  举报