模擬退火入門
阿新 • • 發佈:2020-08-07
入門題:https://www.luogu.com.cn/problem/P1337
#include<cstdio> #include<cmath> #include<ctime> #include<cstdlib> #define RG register #define R RG long double #define RD T*(rand()*2-RAND_MAX)//生成一個[-T*RAND_MAX,T*RAND_MAX)的隨機變動距離 const int N=1009; const long double D=0.97,EPS=1e-14;//更新後二分出了保證極高正確率和較高效率的引數View Codedouble x[N],y[N],w[N]; int n; inline long double calc(R x0,R y0){ R res=0,dx,dy; for(RG int i=1;i<=n;++i){//函式求值 dx=x[i]-x0;dy=y[i]-y0; res+=sqrt(dx*dx+dy*dy)*w[i]; } return res; } int main(){ R T,x0,y0,x1,y1,res,ans,best,bx=0,by=0; RG int i,times=1;//一次的正確率很高的,不放心也可以調大scanf("%d",&n); for(i=1;i<=n;++i){ scanf("%lf%lf%lf",&x[i],&y[i],&w[i]); bx+=x[i];by+=y[i]; }//初始橫縱座標均選擇平均值 best=ans=calc(bx/=n,by/=n); srand(time(NULL)); while(times--/*clock()<CLOCKS_PER_SEC*0.9*/){//比賽的時候試試註釋裡寫的,卡時還是靠譜些 ans=best;x0=bx;y0=by;for(T=100000;T>EPS;T*=D){ x1=x0+RD;y1=y0+RD; res=calc(x1,y1); if(best>res) best=res,bx=x1,by=y1;//更新最優答案 if(ans>res||exp((ans-res)/T)>(long double)rand()/RAND_MAX) ans=res,x0=x1,y0=y1;//接受新解 } }; printf("%.3Lf %.3Lf\n",bx,by); return 0; }