转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出球上4个点,求球心坐标
http://acm.hfut.edu.cn/OnlineJudge/
赤果果的是模拟退火啊。。。
当时完全不知道,果断YY了一下之后只能放弃。
对于每一个点,我们计算一下与目标圆心的误差。方差???
随机一点,然后设定一个初始步长,每一次随机30个方向走出去,如果比当前位置更优,则更新
直到步长达到要求的精度。
这题给的时限有3s,范围是1000,貌似精度要求还是很高的,每次step减小0.05倍都不能过。
最终1s+过了,效率不高。
#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<sstream>
#include<ctime>
#include<cassert>
#define LL long long
#define eps 1e-8
#define inf 999999.0
#define zero(a) fabs(a)<eps
#define N 20
#define pi acos(-1.0)
using namespace std;
struct Point{
double x,y,z;
bool check(){
if(fabs(x)<500+eps&&fabs(z)<500+eps&&fabs(y)<500+eps)
return true;
return false;
}
}p[4],cur,central;
double dist(Point p1,Point p2){
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z));
}
//当前状态与目标态的误差
double Get_Diff(Point cen){
double diff=0,sum=0,dis[4];
for(int i=0;i<4;i++){
dis[i]=dist(cen,p[i]);
sum+=dis[i];
}
sum/=4;
for(int i=0;i<4;i++)
diff+=(dis[i]-sum)*(dis[i]-sum);
return diff;
}
int main(){
int t,cas=0;
scanf("%d",&t);
while(t--){
for(int i=0;i<4;i++)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
central.x=central.y=central.z=0;
//步长初始1000,初始位置0,0,0
double step=1000,best=Get_Diff(central);
while(step>0.001){
for(int i=0;i<30;i++){
//随机一个方向
double a=(rand()%30000+1)/30000.0*pi*2;
double b=(rand()%30000+1)/30000.0*pi*2;
cur.x=central.x+step*sin(a)*cos(b);
cur.y=central.y+step*sin(a)*sin(b);
cur.z=central.z+step*cos(a);
if(!cur.check()) continue;
double tmp=Get_Diff(cur);
if(tmp+eps<best){
best=tmp;
central=cur;
}
}
step*=0.95;
}
printf("Case #%d: %.1f %.1f %.1f\n",++cas,central.x,central.y,central.z);
}
return 0;
}