【概述】

爬山法(Hill Climbing,HC)是一种局部择优的贪心搜索算法,其本质上是梯度下降法。

该算法每次从当前的节点开始,与周围的邻接点进行比较:

  • 若当前节点是最大的,那么返回当前节点,作为最大值
  • 若当前节点是最小的,就用最高的邻接点替换当前节点,从而实现向山峰的高处攀爬的目的

如此循环往复,直到达到最高点为止。

但该算法的主要问题是:局部最大,即某个节点会比周围任何一个邻居都高,但只是局部最优解,并非全局最优解。

如下图,在处于当前解时,爬山法搜索到局部最优解后,就会停止搜索,因为在局部最优解这个点,无论向哪个方向小幅度的移动,都无法得到更优解

机器学习 梯度爬山可视化 爬山法和梯度下降_机器学习 梯度爬山可视化

此外,其还存在以下两种问题:

  • 高地问题:搜索一旦到达高地,就无法确定搜索最佳方向,会产生随机走动,使得搜索效率降低
  • 山脊问题:搜索可能会在山脊的两面来回震荡,前进步伐很小

当出现以上问题后,只能随机重启爬山算法来解决。

【主要思路】

首先,随机选择一个登山的初始时间 T,这个参数是随机选择

然后,只要当 T 大于一个边界值 EPS 时,就将当前点与其邻接点进行比较:

  • 如果 res<newRes,转移答案,并记录新坐标点 pos
  • 如果 res>newRes,不转移

之后,根据记录下来的新坐标点 pos,去转移状态,一般为:sta = sta + (node[pos] - sta) * T;

最后,对 T 乘以一个小于但十分接近于 1 的数 delta,以体现时间对答案的影响。

不断重复上述步骤,直到邻接点中不再有比起大的点。

int getPos(double x) {//比较答案并获取新坐标点
    int pos;//新坐标点
    double res = -INF;
    for (int i = 1; i <= n; i++) {
        double newRes = getRes(x, node[i]);//获取新状态答案
        if (newRes > res) { //比较答案
            res = newRes; //更新结果
            pos = i; //记录新坐标点
        }
    }
    return pos;
}
void HC(double &x,double &y) {
    double T = 1;
    while (T > EPS) {
        int pos = getPos(x);//获取下一状态的坐标
        sta = sta + (node[pos] - x) * T;//转移x状态
        T *= 0.96;
    }
}