最小球覆盖算法
####算法简介:给出n个点,求出一个最小的球体,让所有的点都在球内或球面上
###算法思想:模拟退火算法(退火算法详解见:https://blog.csdn.net/u010712012/article/details/82262260)博主讲的很好!
###板子:
题目:POJ2069 Super Star
ACcode
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
const int MAXN=105;
const double EPS=1e-6;
struct Point{
double x,y,z;
Point(double _x=0,double _y=0,double _z=0){
x=_x;y=_y;z=_z;
}
};
Point Dots[MAXN];
int n;
double Distance(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 Solve(){
double Step=200,ans=1e9,mt;
Point z=Point(0.0,0.0,0.0);
int s=0;
while(Step>EPS){
for(int i=1;i<=n;++i){
if(Distance(z,Dots[s])<Distance(z,Dots[i])){
s=i;
}
}
mt=Distance(z,Dots[s]);
ans=min(ans,mt);
z.x+=(Dots[s].x-z.x)/mt*Step;
z.y+=(Dots[s].y-z.y)/mt*Step;
z.z+=(Dots[s].z-z.z)/mt*Step;
Step*=0.99;
}return ans;
}
int main(){
//freopen("**.in","r",stdin);
//freopen("**.out","w",stdout);
while(~scanf("%d",&n)){
if(n==0) break;
for(int i=1;i<=n;++i){
double x,y,z;scanf("%lf%lf%lf",&x,&y,&z);
Dots[i]=Point(x,y,z);
}
printf("%.5f\n",Solve());
}
}
###注意:模拟退火算法如果过不了,就改变一下精度。将 EPS改小,Step改大,结果精度会变大
例如:codeforces 20182019-acmicpc-asia-nanjing-regional-contest
ACcode
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
const int MAXN=105;
const double EPS=1e-8;
struct Point{
double x,y,z;
Point(double _x=0,double _y=0,double _z=0){
x=_x;y=_y;z=_z;
}
};
Point Dots[MAXN];
int n;
double Distance(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 Solve(){
double Step=100000,ans=1e9,mt;
Point z=Point(0.0,0.0,0.0);
int s=0;
while(Step>EPS){
for(int i=1;i<=n;++i){
if(Distance(z,Dots[s])<Distance(z,Dots[i])){
s=i;
}
}
mt=Distance(z,Dots[s]);
ans=min(ans,mt);
z.x+=(Dots[s].x-z.x)/mt*Step;
z.y+=(Dots[s].y-z.y)/mt*Step;
z.z+=(Dots[s].z-z.z)/mt*Step;
Step*=0.98;
}return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
double x,y,z;scanf("%lf%lf%lf",&x,&y,&z);
Dots[i]=Point(x,y,z);
}
printf("%.15f",Solve());
}