Loading

SA(模拟退火)学习笔记

也就是个乱搞做法,但是我感觉好好玩。

顾名思义:模拟退火就是模拟退火的算法。

一句话概括:从一个解开始,温度不断降低的同时,找相邻解,如果更优直接接受,否则由当前温度决定接受概率。

展示一张 oiwiki 图:

image

具体地,我们设置一个初始温度 \(t_0\),终止温度 \(t_1\),一个温度下降率 \(\alpha\),一个能量函数 \(f(x)\) 用于表示 \(x\) 的优劣(一般越小越优),一个扰动函数 \(g(x)\),用于找到 \(x\) 相邻解。

算法中,我们只需要维护当前温度 \(t\) 和当前的解 \(x\) 即可。

算法流程如下:

  • \(x\) 赋为一个合法解。

  • \(t \leftarrow t_0\)

  • \(t > t_1\) 时,进行以下循环:

  • \(tx \leftarrow g(x)\)\(\Delta \leftarrow f(tx) - f(x)\)

  • \(\Delta < 0\),即 \(tx\) 更优,那么 \(x \leftarrow tx\);否则根据 Metropolis 法则,我们以 \(\frac{1}{\exp(\frac{\Delta}{t})}\) 的概率 \(x \leftarrow tx\)

  • \(t \leftarrow t \cdot \alpha\)

\(x\) 就是跑出来的解。

举个例子吧,就是这个吊打XXX,这个虽然是单峰函数,不能证明你的退火是否强劲,但是各种题解可以起到体现具体过程的作用。

然后,就是如何调参和设计 \(f\)\(g\) 函数:

  • \(t_0\) 决定了搜索范围,但是也会影响程序时间。

  • \(t_1\)\(\alpha\) 决定了精度。

  • 扰动函数可以直接均匀扰动,即 \(g(x) = x + rand(-r, r)\)\(r\) 视情况而定,一般可以直接和温度呈线性放缩关系,温度越低步长越小,需要尽可能避免迂回。

  • \(f(x)\) 可以根据题目直接来,比如“状态为 \(x\) 时的最小操作次数”。通过确定了 \(f(x)\),我们就可以根据“搜索初期 \(\Delta\)\(t\) 等阶”这一理想状态来确定其它参数了。

技巧。

  • 有的时候需要在同一温度下,多跑几次 \(g\) 函数,多尝试几个解再降温。

  • 多起点搜索。

  • 起点 \(x\) 一般选取那种可以贪心构造/直觉构造,但是并不是最优的较优解,一般这种解可以通过相对少次的 \(g\) 扰动得到最优解。这种情况可以先试试去掉 metropolis 的类爬山算法,找出来的解可能更精准。为什么?metropolis 的作用是帮助你跳出局部最小的坑,而你现在构造出来了一个较优的解,可能只需要一点调整就够了。那么这个时候你大概率已经在最深的谷的一个边坡上,metropolis 只会让你跳出这个谷,从而更难找到答案。

  • 记录全局最优,当然了可以把上次跑出来的结果作为下一次的起点扔进去再跑一遍也行。

比如 NOI2024 百万富翁

这些只是我的个人见解,有一定局限性,还没有经过检验,接下来会尝试几道练习题,并且对以上内容做出可能的改进。

posted @ 2026-05-23 12:20  Trent900  阅读(53)  评论(2)    收藏  举报