模拟退火SA刷题记录
洛谷P1337 [JSOI2004]平衡点 / 吊打XXX
- 基本上是照着别人的代码写的,模拟退火为什么一定能找到答案呢。。。迷惑,,有时间搜一搜证明啥的
- sa步骤:这个是要确定一个(xi,yi)使得函数()值最小,所以先选一个开始的点(这里选的是所有桌子上的点的均值),然后(rand()*2-RAND_MAX)*T就是deltax,deltay,然后再算出移动了这个delta后的函数值,该函数值如果是一个更小的值,则接受,否则如果( exp(-delta/T)*RAND_MAX>rand() )才接受,注意这里的delta是函数值的差值,这个exp(-delta/T)是一个在0,1之间的数。
- 产生移动距离:(rand()*2-RAND_MAX)*T (这样正负都有)
- 以一定的概率接受移动:exp(-delta/T)*RAND_MAX>rand()
- 步骤:找到需要最优化的函数,找到移动方案,徐徐降温直到温度达到exp=1e-15退出,输出答案
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 1010 3 4 using namespace std; 5 int n; 6 double x[nmax],y[nmax],w[nmax]; 7 double ansx,ansy; 8 const double eps=1e-15; 9 10 int cnt=0; 11 12 double f(double nx,double ny){ 13 double tot=0,tmp; 14 for (int i=0; i<n; i++) { 15 tmp=sqrt( (nx-x[i])*(nx-x[i])+(ny-y[i])*(ny-y[i]) ); 16 tot+=tmp*w[i]; 17 } 18 return tot; 19 } 20 21 void sa(){ 22 double t=200.0; 23 while(t>eps){ 24 double nowx=ansx+(rand()*2-RAND_MAX)*t,nowy=ansy+(rand()*2-RAND_MAX)*t; 25 double delta=f(nowx,nowy)-f(ansx,ansy); 26 if( delta<0 || ( exp(-delta/t)*RAND_MAX>rand() ) ) { ansx=nowx; ansy=nowy; } 27 t*=0.998; 28 } 29 } 30 31 int main(){ 32 srand((int)time(NULL)); 33 cin>>n; 34 for (int i=0; i<n; i++) { 35 scanf("%lf%lf%lf",&x[i],&y[i],&w[i]); 36 ansx+=x[i]; 37 ansy+=y[i]; 38 } 39 ansx/=(double)n; 40 ansy/=(double)n; 41 sa(); 42 printf("%.3lf %.3lf\n",ansx,ansy); 43 return 0; 44 }
20182019-acmicpc-asia-nanjing-regional-contest
D Country Meow
- 最小球覆盖。。。没看网上的做法,写了个普通的模拟退火,反正这道题是过了。。好像这题数据很水的
- 看出容易用模拟退火的题的一个特点:答案的精度要求大概在1e-3
- 代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdlib> 5 #include <ctime> 6 #include <cmath> 7 #define nmax 110 8 9 using namespace std; 10 int n; 11 double x[nmax],y[nmax],z[nmax]; 12 const double eps = 1e-15; 13 double ansx,ansy,ansz; 14 15 double f(double nx,double ny,double nz){ 16 double maxa=0; 17 for (int i=0; i<n; i++) { 18 double tx=nx-x[i],ty=ny-y[i],tz=nz-z[i]; 19 maxa=max(maxa,sqrt(tx*tx+ty*ty+tz*tz)); 20 } 21 return maxa; 22 } 23 24 void sa(){ 25 double t=20000.0; 26 while(t>eps){ 27 double tx=ansx+(rand()*2-RAND_MAX)*t,ty=ansy+(rand()*2-RAND_MAX)*t,tz=ansz+(rand()*2-RAND_MAX)*t; 28 double delta=f(tx,ty,tz)-f(ansx,ansy,ansz); 29 if(delta<=0|| ( exp(-delta/t)*RAND_MAX>rand() ) ) ansx=tx,ansy=ty,ansz=tz; 30 t*=0.999; 31 } 32 } 33 34 int main(){ 35 srand((int)time(NULL)); 36 cin>>n; 37 double minx=20000000,miny=20000000,minz=20000000,maxx=-20000000,maxy=-20000000,maxz=-20000000; 38 for (int i=0; i<n; i++) { 39 scanf("%lf%lf%lf",&x[i],&y[i],&z[i]); 40 minx=min(minx,x[i]); 41 miny=min(miny,y[i]); 42 minz=min(minz,z[i]); 43 maxx=max(maxx,x[i]); 44 maxy=max(maxy,y[i]); 45 maxz=max(maxz,z[i]); 46 } 47 ansx=minx+(maxx-minx)/2; 48 ansy=miny+(maxy-miny)/2; 49 ansz=minz+(maxz-minz)/2; 50 sa(); 51 sa(); 52 sa(); 53 printf("%lf",f(ansx,ansy,ansz)); 54 return 0; 55 }