利用模拟退火算法求解旅行商问题

模拟退火算法的原理

模拟退火算法(Simulated Annealing, SA)是一种全局优化算法,其灵感来源于物理学中的退火过程。在物理退火过程中,通过逐渐降低系统温度,使物质内部的原子从高能量状态慢慢转变到低能量状态,从而达到晶体结构的优化。模拟退火算法借鉴了这种过程,通过随机搜索和逐步降低"温度"来寻找优化问题的全局最优解。

关键概念
  1. 温度(Temperature): 控制搜索过程中的"探索"与"开发"平衡。高温下允许较大范围的随机搜索,低温下逐渐收敛到局部优化。

  2. 状态(State): 问题的一个解。

  3. 能量(Energy): 目标函数的值,反映当前状态的质量。

  4. 接受概率(Acceptance Probability): 用于决定是否接受一个新的状态,即使它的能量较高,以避免陷入局部最优解。

算法步骤
  1. 初始化温度 TT 和初始状态 SS。

  2. 重复以下步骤直到满足停止条件:

    1. 在当前状态 S 的邻域中随机选择一个新的状态 S'。

    2. 计算状态 S′ 的能量差 ΔE=E(S′)−E(S)。

    3. 如果 ΔE≤0,接受新的状态 S′;否则,以概率接受新的状态。

    4. 减少温度 T。

  3. 返回找到的最优状态。

应用

模拟退火算法广泛应用于组合优化问题和实际工程中的复杂优化问题。常见的应用包括:

  1. 旅行商问题(TSP): 通过模拟退火算法寻找最短路径。

  2. 排程问题: 优化工厂生产调度、考试安排等。

  3. 电路设计: 优化芯片设计中的布局和连线。

  4. 神经网络训练: 优化神经网络参数,避免陷入局部最优解。

旅行商问题求解:

python 复制代码
import numpy as np
import matplotlib.pyplot as plt

# 生成随机城市坐标
def generate_cities(num_cities):
    return np.random.rand(num_cities, 2)

# 计算路径长度
def path_length(cities, path):
    """
    计算给定路径的总长度
    :param cities: 城市坐标的二维数组
    :param path: 城市访问顺序的数组
    :return: 路径的总长度
    """
    return np.sum(np.linalg.norm(cities[path] - cities[np.roll(path, -1)], axis=1))

# 交换路径中的两个城市
def swap_cities(path):
    """
    随机交换路径中的两个城市
    :param path: 城市访问顺序的数组
    """
    i, j = np.random.choice(len(path), 2, replace=False)
    path[i], path[j] = path[j], path[i]

# 模拟退火算法
def simulated_annealing(cities, initial_temp, cooling_rate, num_iterations):
    """
    使用模拟退火算法寻找最短路径
    :param cities: 城市坐标的二维数组
    :param initial_temp: 初始温度
    :param cooling_rate: 降温速率
    :param num_iterations: 迭代次数
    :return: 最佳路径及其长度和每次迭代的路径长度
    """
    # 城市数量
    num_cities = len(cities)
    
    # 初始路径为随机顺序
    current_path = np.arange(num_cities)
    np.random.shuffle(current_path)
    
    # 计算初始路径的长度
    current_length = path_length(cities, current_path)
    
    # 初始化最佳路径和长度
    best_path = current_path.copy()
    best_length = current_length
    
    # 初始化温度
    temp = initial_temp

    # 记录路径长度变化
    lengths = []

    # 开始迭代
    for _ in range(num_iterations):
        # 创建新路径,通过交换当前路径中的两个城市
        new_path = current_path.copy()
        swap_cities(new_path)
        
        # 计算新路径的长度
        new_length = path_length(cities, new_path)
        
        # 计算路径长度差
        delta = new_length - current_length

        # 决定是否接受新路径
        if delta < 0 or np.random.rand() < np.exp(-delta / temp):
            current_path = new_path
            current_length = new_length

            # 更新最佳路径
            if new_length < best_length:
                best_path = new_path
                best_length = new_length

        # 降低温度
        temp *= cooling_rate
        
        # 记录当前路径长度
        lengths.append(current_length)

    return best_path, best_length, lengths


# 参数设置
num_cities = 20
initial_temp = 100
cooling_rate = 0.99
num_iterations = 1000

cities = generate_cities(num_cities)
best_path, best_length, lengths = simulated_annealing(cities, initial_temp, cooling_rate, num_iterations)

# 可视化结果
plt.figure(figsize=(10, 5))

# 绘制城市和最佳路径
plt.subplot(1, 2, 1)
plt.plot(cities[:, 0], cities[:, 1], 'o')
for i in range(num_cities):
    plt.text(cities[i, 0], cities[i, 1], str(i))

for i in range(num_cities):
    plt.plot([cities[best_path[i], 0], cities[best_path[(i+1) % num_cities], 0]],
             [cities[best_path[i], 1], cities[best_path[(i+1) % num_cities], 1]], 'r-')

plt.title(f"Best Path (Length: {best_length:.2f})")

# 绘制路径长度随迭代次数的变化
plt.subplot(1, 2, 2)
plt.plot(lengths)
plt.xlabel('Iteration')
plt.ylabel('Path Length')
plt.title('Path Length over Iterations')

plt.tight_layout()
plt.show()
相关推荐
SeaTunnel4 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
深度研习笔记5 小时前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
碎光拾影5 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库
CCPC不拿奖不改名5 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
Marst Code5 小时前
(python)2026Plotly 库评估:交互式可视化到底值不值得引入?
开发语言·python
databook5 小时前
当散点图不够用时:用 t-SNE 可视化多维数据
python·数据分析·数据可视化
Miao121316 小时前
微服务 API 测试实践:海外某民宿平台如何构建模式驱动测试基础设施
java·开发语言
CRMEB系统商城7 小时前
开源自建还是SaaS订阅?算一笔3年经济账
java·大数据·开发语言·开源
keyipatience8 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
我的xiaodoujiao8 小时前
快速学习Python基础知识详细图文教程9--函数进阶
开发语言·python·学习·测试工具