数学建模赛前备赛——模拟退火算法

一.什么是智能优化算法

智能优化算法本质上是一个优化算法,它通过不断优化模型的参数,使得系统表现达到最优,常见的只能优化算法有很多,比如说蚁群算法,遗传算法以及我们今天的主角------模拟退火算法。

二.模拟算法的前身------爬山算法

爬山算法是一种简单的优化算法,它每次会从当前解的临近解空间中选取一个最优解来作为当前解,直到达到一个局部最优解,但是爬山算法有一个致命的缺陷,就是容易陷入局部最优解,无法跳出局部最优解,从而无法找到全局最优解。像下面这个图:

如果我们从C开始,按照爬山算法,我们最终会陷入局部最优解A,无法找到全局最优解B。其实也是比较好理解,如果把图像看做某个函数的图像,我们找到的只是一个极值点,而不一定是最大值点或者最小值点。

三.模拟退火算法的原理

模拟退火算法是一种基于概率的全局优化算法,它模拟了金属退火的过程,通过在解空间中随机搜索,并利用概率接受较差的解,从而避免陷入局部最优解。模拟退火算法的基本思想是:在高温下,系统中的粒子具有较高的能量,可以自由地移动和交换位置,从而在解空间中搜索到全局最优解。随着温度的降低,粒子的能量逐渐减少,搜索范围逐渐缩小,最终在低温下达到全局最优解。

相比于爬山算法,它引入了温度这一变量设计了一个高温,让粒子的初始状态保持了一个较大活性,可以尝试更多可能性,进而跳出局部最优解,最终找到全局最优解。

四. 算法的实现流程

  • 初始化:初始化温度T(充分大),每个T值的迭代次数L,降温系数alpha(0,1)和终止温度eps(充分小)
  • 随机生成初始解A,计算对应的f(A)
  • 在A附近生成新解,计算增量
  • 判断是否接受新解
  • 降温
  • 判断是否达到终止条件, 如果达到,则结束,否则回到第二步

五.算法的为伪代码实现

我们可以将模拟退火算法写作一个双重迭代算法,分为下面的两个过程:

  • 外循环(退火过程):模拟初始温度很大温度逐渐下降的过程
  • 内循环(搜索过程):模拟某一温度下粒子的跳动过程

首先是外循环:我们首先将固体达到较高的温度(设置一个较高的初始的温度)。然后我们根据降温系数alpha使温度按照一定的比例下降,当达到终止温度eps时,冷却结束,模拟退火结束

python 复制代码
T=2000 #初始温度
eps=1e-8  #终止温度
alpha=0.99  #降温系数(越接近1结果越精确)
while T>eps:
    T*=alpha

然后是内循环:我们首先在当前温度下随机选择一个解,然后计算这个解的适应度值,然后计算新解的适应度值,如果新解的适应度值比当前解的适应度值要高,那么我们就接受新解,否则我们以一定的概率接受新解,这个概率的计算公式为exp(-ΔE/T),其中ΔE为新解的适应度值减去当前解的适应度值,T为当前温度。然后我们更新当前解为新解,继续进行内循环,直到达到终止温度eps,模拟退火结束,大致的流程如下:

大家有可能不是很理解为什么在左边出现更差的结果我们还会有一定的可能接受这个较差的解,而这就是模拟退火算法的核心思想,它允许算法在搜索过程中接受较差的解,从而避免陷入局部最优解,最终找到全局最优解。

六.算法的优缺点

优点:

  • 模拟退火算法是一种全局优化算法,它可以在解空间中搜索到全局最优解,而不会陷入局部最优解。
  • 不受问题约束条件的限制,可以处理各种类型的优化问题。
  • 解与初始解无关,算法的搜索过程是随机的,因此可以避免陷入局部最优解。
  • 可以灵活地调整参数,如初始温度、降温系数和终止温度等,来平衡搜素时间与搜素质量。

缺点:

  • 模拟退火算法的计算复杂度较高,对于大规模问题,计算时间较长。
  • 算法收敛速度较慢,需要较大的计算资源。
  • 需要合适的初始解与参数调整

七.算法的应用

这里我们以旅行商问题(Travelling Salesman Problem,TSP)为例,来演示模拟退火算法的应用。旅行商问题是一个经典的组合优化问题,要求找到一条最短的路径,使得旅行商能够访问所有的城市并返回到起点。旅行商问题是一个NP-hard问题,没有已知的高效算法可以解决所有实例。因此,模拟退火算法是一种有效的解决旅行商问题的方法,我们来看一下如何基于模拟退火算法解决旅行商问题,代码如下:

python 复制代码
import random
import math
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

class SA_TSP:
    def __init__(self, n, X, Y, n_Tk, r, T_f, T0):
        self.n = n  # 城市数量
        self.X = X  # 城市坐标
        self.Y = Y  # 城市坐标
        self.n_Tk = n_Tk  # 内循环次数
        self.r = r  # 降温系数
        self.T_f = T_f  # 终止温度
        self.T0 = T0  # 初始温度
        self.alpha = r  # 温度更新系数
      
    # 计算路径长度
    def fitness(self, X0):
        s = 0
        for i in range(self.n):
            if i != self.n - 1:
                s += np.sqrt((self.X[X0[i]] - self.X[X0[i + 1]]) ** 2 + (self.Y[X0[i]] - self.Y[X0[i + 1]]) ** 2)
            else:
                s += np.sqrt((self.X[X0[i]] - self.X[X0[0]]) ** 2 + (self.Y[X0[i]] - self.Y[X0[0]]) ** 2)
        return s
    
    def exchange(self, X0, i, j):
        X1 = X0.copy()
        X1[i], X1[j] = X1[j], X1[i]
        return X1
    
    def initialX0(self, n):
        X0 = np.random.permutation(range(n))
        return X0
    
    def SA_TSP(self):
        X0 = self.initialX0(self.n)
        # 记录最优路径
        X_min = [X0]
        # 记录最优路径长度
        s_min = [self.fitness(X0)]
        k = 0
        while self.T0 > self.T_f:
            for _ in range(self.n_Tk):
                i, j = random.sample(range(self.n), 2)
                X1 = self.exchange(X0, i, j)
                s1 = self.fitness(X0)
                s2 = self.fitness(X1)
                # 更新历史最优解
                if s2 < min(s_min):
                    s_min.append(s2)
                    X_min.append(X1)
                else:
                    s_min.append(s_min[-1])
                    X_min.append(X_min[-1])

                # 判断是否更新解
                if s2 < s1:
                    X0 = X1
                else:
                    E = math.exp(-(s2 - s1) / self.T0)
                    R = random.uniform(0, 1)
                    if E > R:
                        X0 = X1

                k += 1
            
            self.T0 *= self.alpha  # 温度更新

        # 绘制优化过程
        plt.plot(range(k+1), s_min)
        plt.xlabel('迭代次数')
        plt.ylabel('最优路径长度')
        plt.show()
        
        # 绘制最优路径
        W = X_min[-1]
        for i in range(self.n):
            if i != self.n - 1:
                plt.plot([self.X[W[i]], self.X[W[i + 1]]], [self.Y[W[i]], self.Y[W[i + 1]]], c='plum')
            else:
                plt.plot([self.X[W[i]], self.X[W[0]]], [self.Y[W[i]], self.Y[W[0]]], c='plum')
        plt.scatter(self.X, self.Y, c='red')
        plt.title("路线图")
        plt.xlabel("x")
        plt.ylabel("y")
        plt.show()
        
        return X_min[-1], s_min[-1]

# 定义城市坐标
n = 30
city_x = [41, 37, 54, 25, 7, 2, 68, 71, 54, 83, 64, 18, 22, 83, 91, 25, 24, 58, 71, 74, 87,
          18, 13, 82, 62, 58, 45, 41, 44, 4]
city_y = [94, 84, 67, 62, 64, 99, 58, 44, 62, 69, 60, 54, 60, 46, 38, 38, 42, 69, 71, 78, 76,
          40, 40, 7, 32, 35, 21, 26, 35, 50]
# 内循环的迭代次数
n_Tk = 300
# 降温变化
r = 0.9
# 终止温度
T_f = 0.001
# 初始温度
T0 = 2000
# 创建对象
city30 = SA_TSP(n, city_x, city_y, n_Tk, r, T_f, T0)
# 方法
Xmin, smin = city30.SA_TSP()
print("最短路径为:", Xmin)
print("最短路径长度为:", smin)

运行结果如下:

相比于其他智能优化算法,模拟退火算法适用范围光,全局搜素能力强,不容易陷入局部最优解,这些都是我们可以在论文中去体现的东西,今天的算法介绍就到此为止了,下篇见

相关推荐
Jerry2 小时前
LeetCode 459. 重复的子字符串
算法
海石4 小时前
1500分的题目,确实有实力,不过还是我略胜一筹
算法·leetcode
海石4 小时前
【记忆化搜索】条条大路通AC,走好适合你的那一条,走到后再考虑走得快
算法·leetcode
Jerry6 小时前
LeetCode 151. 反转字符串中的单词
算法
a1117769 小时前
LM 算法迭代过程动画演示(SLAM)
算法
头茬韭菜9 小时前
Context 的生死抉择:四层压缩、截断算法与 Session Memory
算法·ai
Jerry9 小时前
LeetCode 541. 反转字符串 II
算法
Jerry9 小时前
LeetCode 344. 反转字符串
算法
搞科研的小刘选手10 小时前
【香港大学主办&IEEE出版】第六届计算机视觉、应用与算法国际学术会议(CVAA 2026)
算法·计算机视觉·应用·学术会议
Java小白笔记10 小时前
Codex config.toml配置实战指南
人工智能·算法·chatgpt·ai编程·集成学习