2018Nanjing – D 模拟退火

NanjingOnsite:三维坐标下给出$n$个点$p_i$,找到一个点$best$使得$max_{i=1}^ndis(best,p_i)$最小,$n\le 100$

最小球覆盖呵呵

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 103;
const double PI = acos(-1);
const double EPS = 1e-6;
int n;
double ans;
struct Point{
    double x,y,z;
}p[MAXN],now,best;
double dis(Point &a,Point &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 rand01(){
    return (rand()%1000+1.0)/1000.0;
}
double lambda(Point cur){
    double res=0;
    for(int i=1;i<=n;i++){
        res=max(dis(cur,p[i]),res);
    }
    if(res<ans) best=cur,ans=res;
    return res;
}
int main(){
    //freopen("stdin.txt","r",stdin);
    srand(19260817);
    while(~scanf("%d",&n)){
        double nx=0,ny=0,nz=0;
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
            nx+=p[i].x/n;
            ny+=p[i].y/n;
            nz+=p[i].z/n;
        }
        best=now=(Point){nx,ny,nz};ans=0;
        for(int i=1;i<=n;i++){
            ans=max(ans,dis(best,p[i]));
        }
        double T=2e6;
        while(T>EPS){
            double dx=now.x+T*(rand01()*2-1);
            double dy=now.y+T*(rand01()*2-1);
            double dz=now.z+T*(rand01()*2-1);
            Point tmp=(Point){dx,dy,dz};
            double t1=lambda(now),t2=lambda(tmp);
            double de=t1-t2;
            if(de>=0||exp(de/T)>=rand01()){
                now=tmp;
            }
            T*=0.99;
        }
        int times=2e6;
        while(times--){
            double dx=best.x+rand01()*(rand01()*2-1);
            double dy=best.y+rand01()*(rand01()*2-1);
            double dz=best.z+rand01()*(rand01()*2-1);
            lambda((Point){dx,dy,dz});
        }
        printf("%.5lf\n",lambda(best));
    }
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注