题意:让你求空间内n个点的最小覆盖球。
模拟退火随机走的时候主要有这几种走法:①随机旋转角度。
②直接不随机,往最远的点的方向走,仅仅在尝试接受解的时候用概率。(最小圆/球覆盖时常用)
③往所有点的方向的总和走,仅仅在尝试接受解的时候用概率。(费马点时常用)
像这题,我用第一种最暴力的随机,死活过不了……
#include<cstdio> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const double EPS=0.00000001; const double PI=acos(-1.0); struct Point{ double x,y,z; Point(const double &x,const double &y,const double &z){ this->x=x; this->y=y; this->z=z; } Point(){} void read(){ scanf("%lf%lf%lf",&x,&y,&z); } double length(){ return sqrt(x*x+y*y+z*z); } }a[35],p,allp; double ans,allans; int n; typedef Point Vector; Vector operator - (const Point &a,const Point &b){ return Vector(a.x-b.x,a.y-b.y,a.z-b.z); } Vector operator + (const Vector &a,const Vector &b){ return Vector(a.x+b.x,a.y+b.y,a.z+b.z); } Vector operator * (const double &K,const Vector &v){ return Vector(K*v.x,K*v.y,K*v.z); } double calc(Point p){ double res=0.0; for(int i=1;i<=n;++i){ res=max(res,(a[i]-p).length()); } return res; } //double ran(){ // int fm=rand()%10000+1; // return ((rand()&1) ? -1.0 : 1.0)*((double)(rand()%(fm+1))/(double)fm); //} Vector unit(Vector v){ double l=v.length(); return Vector(v.x/l,v.y/l,v.z/l); } int main(){ srand(233); //freopen("poj2069.in","r",stdin); while(1){ scanf("%d",&n); if(!n){ return 0; } allans=100000.0; for(int i=1;i<=n;++i){ a[i].read(); } // for(int j=1;j<=n;++j){ p=a[1]; ans=calc(p); double T=sqrt(20000.0); while(T>EPS){ double bestnow=100000.0; Point besttp; // for(int i=1;i<=30;++i){ // double rad=(double)(rand()%10000+1)/10000.0*2.0*PI; int to; double far=0.0; for(int k=1;k<=n;++k){ double tmp=(a[k]-p).length(); if(tmp>far){ far=tmp; to=k; } } Point tp=p+T*unit(a[to]-p); double now=calc(tp); if(now<bestnow){ bestnow=now; besttp=tp; } // } if(bestnow-100000.0<-EPS && (bestnow<ans || exp((ans-bestnow)/T)*10000.0>(double)(rand()%10000))){ ans=bestnow; p=besttp; } T*=0.99; } if(ans<allans){ allans=ans; // allp=p; } // } printf("%.5lf ",fabs(allans)); } return 0; }