模拟退火学习笔记
膜你颓祸
退火
在每个温度都有几率跳到一个劣与当前的位置,温度越低,劣解的采纳率更低
因为在每个温度都有足够的时间来找到合适的位置,所以最后答案接近正确
模拟退火
就是在解决一类问题中模拟上述方法
形式化地,对于当前一个新解\(f(x)\),有
- \(f(x')>f(x)\),取此解
- \(f(x')<f(x)\),以一定的概率取此解
优缺点
优点:适用性强
缺点:能否AC看运气(概率问题),仅限于偏分使用(需要卡时
伪代码
void sa(){ double t=200.0; while(t>eps){ for (情况总数){ newAns=使用这种情况下的答案 delta=f(newans)-f(nowans)(f:估价) if( delta满足条件 || ( exp(-delta/t)*RAND_MAX>rand() ) { nowans=newans; } } t*=decTemp; } }
吊打LCY(模板)
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<algorithm> #include<cstdlib> #include<cmath> using namespace std; #define db double int n; const int N = 1001; double x[N],y[N],w[N]; double ansx,ansy; const db eps=1e-18; int cnt=0; inline int read(){ int x=0,pos=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-' ) pos=0; for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; return pos?x:-x; } double f(double nx,double ny){ double tot=0; for(int i=1;i<=n;i++){ tot+=w[i]*(db)sqrt((nx-(x[i]))*(nx-(x[i]))+(ny-y[i])*(ny-y[i])); } return tot; } void sa(){ double t=200; while(t>eps){ double nowx=ansx+(rand()*2-RAND_MAX)*t,nowy=ansy+(rand()*2-RAND_MAX)*t; double delta=f(nowx,nowy)-f(ansx,ansy); if(delta<0||(exp(-delta/t)*((db)(RAND_MAX))>((db)(rand())))){ansx=nowx,ansy=nowy;} //exp(-x)在x越小越接近1,即温度越大或者与当前最优解越接近取此答案 t*=0.998; } } int main(){ srand(time(0)+19260817); n=read(); for(int i=1;i<=n;i++){ scanf("%lf%lf%lf",&x[i],&y[i],&w[i]); ansx+=x[i]; ansy+=y[i]; } ansx=ansx/(db)(n); ansy=ansy/(db)(n); sa(); printf("%.3lf %.3lf\n",ansx,ansy); return 0; }