转载请注明出处,谢谢 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; }