浅谈模拟退火
前言
早就想写了
但是因为THUWC的有一题模拟退火符号打反而痛失一等,很长一段时间不想见退火
正文
模拟退火的方法适用于一些最优性的问题里,把问题抽象成一个毫无规律的函数,最优解就是函数的最高点或最低点
以最高点为例
一般是贪心是往高处爬,但是得到的是局部最优解而不是全局最优解.
这时候就需要引入模拟退火
模拟退火算法来源于固体退火原理,是一种基于概率的算法,将固体加温至充分高,再让其徐徐冷却,加温时,
固体内部粒子随温升变为无序状,内能增大,而徐徐冷却时粒子渐趋有序,在每个温度都达到平衡态,最后在
常温时达到基态,内能减为最小。——百度百科
一种通俗的说法就是有一只喝醉了的兔子,它要找到最高的山峰,一开始醉得不清,大概率会走向更低的地方,后面渐渐清醒,走向更低的地方的概率也随之减少
模拟退火算法就是模拟这一过程
用一句话概括算法就是:随机一个新状态,如果新状态更优就更新答案,否则以一定概率接受新状态,接受的概率随温度的降低而减少。
算法描述来自oi-wiki
降温就是顶一个初始温度
T
T
T和最终温度
T
0
T_0
T0,当
T
<
=
T
0
T<=T_0
T<=T0时就退完了,还有一个退火系数
d
=
[
0.95
,
1.0
]
d=[0.95,1.0]
d=[0.95,1.0]降温就是
T
∗
d
T*d
T∗d
可能要问为什么上面是
e
−
Δ
E
T
\large e^{\frac{-\Delta E}{T}}
eT−ΔE
主要是为了方便,首先看看
y
=
e
x
y=e^x
y=ex的图像
可以发现当
x
<
0
x<0
x<0的时候
y
=
(
0
,
1
)
y=(0,1)
y=(0,1)且随
x
x
x的增大而增大
这个性质就非常好了
刚好满足
Δ
E
\large \Delta E
ΔE越大,接受的概率越小,
T
\large T
T越大,接受的概率越大
主要部分的代码长这样
code:
void SA() {
for(double t = Bt; t > Et; t = t * Ct) {
int x = rand() % n + 1, y = rand() % n + 1;//随机一个新状态
calc(); //计算新状态的答案
if(ans < ANS) ANS = ans,nowx = x, nowy = y;//如果小于最优解就接受
else if(exp((ANS - ans)*1.0 / t) > (double)rand() / RAND_MAX)
//否则有一定概率接受, (double)rand() / RAND_MAX的取值是在[0,1]之间的
//这里的符号一定不能打错!!!!(血的教训)
}
}
反正求最优解的问题都可以用退火试一下,反正代码又不长