模拟退火学习笔记
膜你颓祸
退火
在每个温度都有几率跳到一个劣与当前的位置,温度越低,劣解的采纳率更低
因为在每个温度都有足够的时间来找到合适的位置,所以最后答案接近正确
模拟退火
就是在解决一类问题中模拟上述方法
形式化地,对于当前一个新解(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
",ansx,ansy);
return 0;
}