前言
因为听说打得一手好随机化搜索的yyb据佬在考场上D2T3重测前拿下90分怒虐全场,所以蒟蒻也闻风而动了
网上好多博客都讲得十分高大上啊欺负我这种什么也不会的蒟蒻
于是蒟蒻就想尝试用一种更浅显通俗的方式去理解它
算法简述
模拟退火适用的问题通常是一些求最优解的问题
比如,把问题抽象地看成一个长成这样的毫无规律的函数,而最优解就是函数的最低点
众所周知,对于一个没有办法在多项式复杂度的算法下完成求解的问题,我们通常会想到一种简单粗暴的方法——贪心
选择问题的某一个状态,然后不断向更优的情况靠近
比如从A出发,可以获得局部最优解B,但这显然不是全局最优解
显然,这样做的局限性是,过于局限在局部的一个凹部分而无法跳出去去寻找更优的解
原理
为了解决这一问题,科学家们想到了物理的退火降温的过程——
一个处于很高温度的物体,现在要给它降温,使物体内能降到最低。
我们常规的思维是,越快越好,让它的温度迅速地降低。
然而,实际上,过快地降温使得物体来不及有序地收缩,难以形成结晶。而结晶态,才是物体真正内能降到最低的形态。
正确的做法,是徐徐降温,也就是退火,才能使得物体的每一个粒子都有足够的时间找到自己的最佳位置并紧密有序地排列。开始温度高的时候,粒子活跃地运动并逐渐找到一个合适的状态。在这过程中温度也会越降越低,温度低下来了,那么粒子也渐渐稳定下来,相较于以前不那么活跃了。这时候就可以慢慢形成最终稳定的结晶态了。
那么,我们可不可以把找到最优解,与形成结晶态,这两个过程联系在一起呢?
于是,模拟退火诞生了。
实现过程
我们需要设定这几个参数,模拟退火过程
- (T)——温度
- (Delta T)——温度变化率,每次温度等于上一次温度乘上(Delta T),实际应用时一般取(0.95-0.99),模拟徐徐降温
再定义一些量
- (x)——当前选择的解
- (Delta x)——解变动值
- (x_1)——当前的目标解,等于(x+Delta x)
- (Delta f)——当前解的函数值与目标解函数值之差,等于(f(x)-f(x_1))
我们给一个初始解(x),并让它不断变动。要模拟变动的大小随温度的降低而降低,我们每次的(Delta x)应该在一个大小与(T)成正比的值域内随机取值。
这时候我们就要考虑是否将当前解变为目标解。因为我们还是需要贪心,所以如果(f(x_1)<f(x)),那么接受目标解,(x=x_1)
那如果(f(x_1)>f(x))呢?我们当然要以一定概率接受它啦,这样才能跳出局部的限制,去搜寻更优的解,弥补贪心的局限性。那么这个概率应该是多少呢?同样要模拟变动的大小随温度的降低而降低。科学家经过理论分析,得出这个概率应该是(e^{Delta f over T})
如此反复选择直到(T)趋近于0(可以设一个EPS)这时候我们认为我们当前的(x)就是最优解
用图片来描述的话,就拿上面那个图像寻找最优解为例
首先经过大幅波动,当前解由A->B->C,找到了一个比较满意的解。
但还不能满足。由于温度还比较大,此时接受了一些不比当前解优的目标解,C->D->E,成功地爬了上去。而温度还在慢慢减小。
终于,发现了一个更优解F,成功跳出了那个非常宽的局部凹函数
这时候,温度越来越小了,很难再次接受不比当前解优的目标解,再次翻出去。解终于渐渐趋于稳定,并最终到达了G,找到了最优解
如此看来,基于随机的模拟退火能很大程度上提高正确率,但也不可能完全正确。上面的例子只是随意模拟出的一个情况。所以要多跑几遍,取每一次得到的解的最优值。
关于参数
众所周知,模拟退火最麻烦的地方在调参,只有合适的参数才能在一定的时间内很大概率跑出最优解。
蒟蒻的经验暂时还不足呢qwq,不过也随便谈谈吧。
首先,根据数据范围和精度要求,可以基本确定EPS的大小了,不过也需要尝试手动微调。
比较麻烦的是温度和变动率。首先不必顾虑,都开大一点,先把最优解跑出来。
然后,手动二分吧,注意每个二分的值要多跑几遍,因为模拟退火有偶然性,一次跑出最优解不代表大部分时候都能。
不过因为有两个量,还不能直接二分,应该二分套二分比较合适
update:考试的时候写提答,总结了一种方法:观察法
一边退火一边输出当前的温度、解等信息,通过观察大致感受一下解的降低速率
一般来说,如果解的降低速率比较均匀,跑出来的最优解也就好一些
不均匀的话,就调整参数,将解的降低速率较快的时间段的(Delta T)变大一点,速率就能减慢一点。反之同理。
题目
洛谷P1337 【[JSOI2004]平衡点 / 吊打XXX】
模拟退火并不是正解,不过是一道入手好题,因为各部分实现都很方便