模拟退火、爬山
模拟退火
模拟退火算法(Simulate Anneal,SA)是一种基于随机化的乱搞算法,常用于解决求解多峰函数最大值。
常见处理问题有:平面最小能量点(如 P1337 [JSOI2004]平衡点 / 吊打XXX,P5544 [JSOI2016]炸弹攻击1)、最优分配或随机分配最大收益(如 P3878 [TJOI2010]分金币)等等。
其中最为核心的就是模拟金属退火的操作,我们对答案接受的可能性随着温度的降低而减少,大致代码如下:
inline void sa()
{
double t=5000.0,cool=0.996,eps=1e-15;
while(t>eps)
{
double tx=ansx+(rand()*2-RAND_MAX)*t;
double ty=ansy+(rand()*2-RAND_MAX)*t;
int Now=calc(tx,ty);
double de=Now-ans; // 这里求解的是最大值
if(de>0) ans=Now,ansx=tx,ansy=ty;
else if(exp(-de/t)*RAND_MAX<rand())
ansx=tx,ansy=ty;
// 若需要求解最小值,将上面两个 if 的不等号取反
t*=cool;
}
}
其他例题:P3936 Coloring,P2538 [SCOI2008]城堡,P2210 Haywire。
关于参数的一些小问题:可以设初始温度在 \(\texttt{3000}^\circ\),下降温度比例约为 \(\texttt{0.996}\),\(\texttt{eps}\) 设为 \(\texttt{1e-12}\)。
如果发现正确性不够,可以多跑几次,不用更改上面的温度等。