浅谈模拟退火

前言

早就想写了
但是因为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 Td

可能要问为什么上面是 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]之间的
		 		//这里的符号一定不能打错!!!!(血的教训)
	}
}

反正求最优解的问题都可以用退火试一下,反正代码又不长

posted @ 2020-05-12 09:31  lahlah  阅读(78)  评论(0编辑  收藏  举报