爬山算法(Hill Climbing )
爬山算法(Hill Climbing )是一种局部择优的方法,采用启发式方法,是对深度优先搜索的一种改进,它利用反馈信息帮助生成解的决策。 属于人工智能算法的一种。
有一些问题,是找全局最大值的。题目所述出自变量与值之间的关系是函数,而这函数图像往往像山的形状,可能有许多局部最大、局部最小。于是“爬山”、“高地”、“山脊”等词形象地表示了算法的作用与函数图像的某些部分.
解决这类问题一般有两种方法:爬山算法(Hill Climbing )与模拟退火(Simulated Annealing)。常用的为模拟退火,它往往可以得到最优解。不过这里先介绍爬山算法。
爬山算法是一种简单的贪心搜索算法,该算法每次从当前解的临近解空间中选择一个最优解作为当前解,直到达到一个局部最优解。
爬山算法的优点为:避免遍历,通过启发选择部分节点,从而达到提高效率的目的。但是有缺点:只能找到局部最优,一般找不到全局最优解;搜索一旦到达高地,就无法确定搜索最佳方向,会产生随机走动,使得搜索效率降低;搜索可能会在山脊的两面来回震荡,前进步伐很小。
下图反应了爬山算法相对于模拟退火的目光短浅之处(模拟退火也是随机算法,不一定可以找到最优解,但大部分情况可以找到)
模拟退火(Simulated Annealing)
退火是物理热力学里的概念。退火是将金属加热到一定温度,保持足够时间,然后以适宜速度冷却的一种金属热处理工艺。我们把这个过程模拟一下,就叫模拟退火(Simulated Annealing)。
爬山算法就是贪心法。而模拟退火是一种随机搜索算法。它的描述是这样的:
若移动后得到更优解,则总是接受该移动
若移动后的解比当前解要差,则以一定的概率接受移动,而且这个概率随着时间推移逐渐降低。
根据热力学的原理,降温的概率 P P P表示为:
Δ E:当前状态与新状态的能量差
k k k:常数
T T T:时间
Δ E > 0 \Delta E>0 ΔE>0时,一定接受。 Δ E < 0 \Delta E<0 ΔE<0时就不一定了,并且x越来越小的时,函数值越来越趋近与0,这也就是说随着T的增加,概率越来越小,趋向稳定。
我们要维护T。初始温度为 T 0 T_0 T0(较大),降温系数为 d d d,最终温度为 T k T_k Tk。
首先让 T = T 0 T = T_0 T=T0;每次让 T = d T T=dT T=dT; T < T k T<T_k T<Tk时降温结束,此时为最优解。
调参时一般会调 d d d( 0 < d < 1 0<d<1 0<d<1)。 d d d过大降温慢,得到最优解的可能性大(容易 T L E TLE TLE); d d d过小降温快,但得到最优解的可能性小(容易 W A WA WA);
那模拟退火具体怎么使用代码实现?
每次循环内有 4 步:
根据当前解找到下一个解
计算下一个解的 “能量”
决定是否要接受这个新解
降温
找下一个解时一般生成随机区间[−1,1]的随机数再乘上T作为差值. 得到一个[−T,T]的随机值作为差值,也就是说T越低,它随机到下一步的范围就越小。
伪代码:
当前温度 = 初始温度;
while 当前温度 > 终温:
根据T随机生成下一步;
计算出下一步的能量;
计算能量差;
if 接受:更新答案;
当前温度 乘以 降温系数;
推荐几道模拟退火的例题:
HDU 2899 比较好的入门题
HDU 3932 二维相关
NOIP2017 宝藏 骗分甚至AC
POJ 3311 TSP问题
例题讲解
HDU 2899 (求函数最值)
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
using namespace std;
double y;
double F(double x) {
return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3)
+ 5 * pow(x, 2) - y * x;
}
double Rand01() {
return rand() / (double)RAND_MAX;
}