前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >人工智能基础-局部搜索算法

人工智能基础-局部搜索算法

作者头像
DearXuan
发布2022-01-19 18:52:35
5470
发布2022-01-19 18:52:35
举报

爬山算法

算法概念

爬山算法类似于贪心搜索,它每次都会查找附近节点里的最优节点,并移动到最优节点,如此循环便找到最优解,但是它只能找到局部的最优解,而非整体最优解

问题示例

以搜索最高点为例,已知山坡的高度f(x,y)满足

DearXuan
DearXuan

给定初始地点,找到最高点

显然x和y的范围是无穷大的,无法遍历全部结果,因此采用爬山算法找到局部最优解

代码语言:javascript
复制
#include <iostream>
#include <cmath>
 
using namespace std;
 
#define pai 3.141592653589
#define e 2.718281828284
#define step 0.1
#define Node _Node
 
//计算(x,y)处的高度
double f(double x, double y) {
    double x2 = x * x, y2 = y * y;
    double x_2 = (x - 2) * (x - 2), y_2 = (y - 3) * (y - 3);
    return pow(e, -(x2 + y2)) + 4 * pow(e, -(x_2 + y_2));
}
 
//节点类
class _Node {
public:
    double x;//x坐标
    double y;//y坐标
    double height;//高度
    void init(double x, double y);//初始化节点
};
 
void _Node::init(double x, double y) {
    this->x = x;
    this->y = y;
    this->height = f(x, y);
}
 
//查找附近的最高点并返回
Node Search(Node node) {
    double x = node.x;
    double y = node.y;
    Node nodes[4];
    nodes[0].init(x + step, y);
    nodes[1].init(x - step, y);
    nodes[2].init(x, y + step);
    nodes[3].init(x, y - step);
    for (Node &i: nodes) {
        //查找最高点
        if (i.height > node.height) {
            node = i;
        }
    }
    return node;
}
 
int main() {
    Node node;
    Node nearly;
    double x, y;
    scanf("%ld%lf", &x, &y);
    node.init(x, y);
    while (true) {
        nearly = Search(node);
        if (nearly.height == node.height) {
            //如果最高点是自己或者和自己一样高,说明已经找到局部最优解
            break;
        } else {
            //最高点不是自己,继续查找
            node = nearly;
        }
    }
    printf("\nx: %lf\ny: %lf\nHeight: %lf\n", node.x, node.y, node.height);
    return 0;
}

初始位置为(0.5, 0.5)

DearXuan
DearXuan

初始位置为(5, 5)

DearXuan
DearXuan

模拟退火算法

Metropolis准则

Metropolis准则使用随机因素来确定是否接收新状态

设时间为t, 温度为T, 状态函数F(t), 下一状态F(t+1)

接收(t+1)状态的概率为P,且P满足

DearXuan
DearXuan

其中k是[0,1]范围内的实数

算法概念

模拟退火算法遵循Metropolis准则,按照一定的概率接受下一个解,即使它是非最优解,因此随着迭代次数的增加,最终会趋向于全局最优解

问题示例

已知山坡高度f(x)满足

DearXuan
DearXuan

求x∈[0, 20]时山坡的最低点

通过图像可以看出该函数拥有多个极小值点

DearXuan
DearXuan

如果使用爬山算法会在其中一个极小值点结束

代码语言:javascript
复制
#include <iostream>
#include <cmath>
 
using namespace std;
 
#define ERROR INT32_MAX
#define step 0.1
 
double x_min = 0;//最小值
double x_max = 20;//最大值
 
//计算函数值
double f(double x) {
    if (x < x_min || x > x_max) {
        //超出界限,返回int32的最大值
        return ERROR;
    } else {
        return x + sin(x) - 2 * cos(2 * x);
    }
}
 
//使用爬山算法求解
int main() {
    double x;
    cin >> x;//输入初始位置
    double height = f(x);//状态值(高度)
    for (;;) {
        //获取x的左边和右边的状态值
        double x1 = x + step, x2 = x - step;
        double h1 = f(x1), h2 = f(x2);
        //用x1和h1保存两边的较低点
        if (h2 < h1) {
            h1 = h2;
            x1 = x2;
        }
        //将两边的较优解与当前解比较
        if (h1 < height) {
            //存在比当前位置更优的解,则向该位置移动
            x = x1;
            height = h1;
        } else {
            //两边都不存在更优的解,退出循环
            break;
        }
    }
    printf("x: %lf\nh: %lf\n", x, height);
    return 0;
}
DearXuan
DearXuan

显然x=12.3并不是全局的最优解,而是局部最优解

现使用模拟退火算法的思路改良爬山算法:

  1. 每次从当前解周围随机取一个新的解
  2. 如果新的解更优,则直接替换当前解
  3. 如果当前解更优,则按照一定概率接受新的解
代码语言:javascript
复制
#include <iostream>
#include <cmath>
#include <sysinfoapi.h>
 
using namespace std;
 
#define step 0.1
 
double x_min = 0;//最小值
double x_max = 20;//最大值
 
double k = 0.9;
double T = 50000;//初始温度
double dT = 0.99;//下降倍率
double minT = 100;//最低温度
int num = 50000;//迭代次数
 
double x;
double height;
double x_next;
double height_next;
 
//计算函数值
double f(double x) {
    return x + sin(x) - 2 * cos(2 * x);
}
 
//获取start到end的随机数
double random(double start, double end) {
    double len = end - start;//区间长度
    double r = rand() / ((double) RAND_MAX + 1.0);//0到1之间的随机数
    return start + r * len;
}
 
//使用模拟退火算法求解
int main() {
    cin >> x;//输入初始位置
    height = f(x);
    while (T > minT) {
        //重置随机数种子
        srand(GetTickCount());
        for (int i = 0; i < num; i++) {
            //添加(-0.5, 0.5)的扰动,获取新的解
            x_next = x + random(-1, 1);
            //确保新的解不越界,否则直接跳过
            if (x_next >= x_min && x_next <= x_max) {
                height_next = f(x_next);
                if (height_next < height) {
                    //新的解更优,直接替换当前解
                    x = x_next;
                    height = height_next;
                } else {
                    //当前解更优,以一定的概率接受新的解
                    double dx = x_next - x;
                    double p = exp(dx / (T * k));
                    if (p < random(0, 1)) {
                        x = x_next;
                        height = height_next;
                    }
                }
            }
        }
        T *= dT;
    }
    printf("x: %lf\nh: %lf\n", x, height);
    return 0;
}
DearXuan
DearXuan

成功找到全局最优解

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021年11月5日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 爬山算法
    • 算法概念
      • 问题示例
      • 模拟退火算法
        • Metropolis准则
          • 算法概念
            • 问题示例
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档