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

模拟退火算法的原理

模拟退火算法(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()
相关推荐
小小张说故事18 分钟前
Python 的 str 为什么设计成不可变?拆开字符串驻留、字符串池,以及 += 拼接到底慢在哪
后端·python
ljt272496066121 分钟前
Python笔记(十一)--Numpy(一)
笔记·python·numpy
时早玖沐26 分钟前
KOOK「找不到语音频道」:同一个错误假设,我犯了三次
python·开源·ai编程
_冷眸_28 分钟前
Python 调用大模型 API:最小请求、Base URL 和 401/404 排查
开发语言·人工智能·python
niucloud-admin38 分钟前
NIUCLOUD PHP SAAS上门家政使用文档:服务保障
java·开发语言·php
Dumbness1 小时前
UIA 读微信群消息没有 id,怎么判断哪条是新的:后缀对齐在翻历史和撤回时整屏重报
python·算法
甜到心里的蛋糕1 小时前
从 QQ 机器人到 B 站 AI 运营:一套可复现的视频流水线踩坑实录
运维·人工智能·python·自动化·视频制作
张驰咨询公司1 小时前
六西格玛Python DOE试验矩阵:3因子2水平生成与验算
python·六西格玛·实验设计·itertools·doe试验矩阵
熊猫钓鱼>_>1 小时前
鸿蒙 PC 三方库适配复盘:libfvad 1.0 —— 把 WebRTC VAD 做成能装进采集链路的静态库
服务器·开发语言·华为·harmonyos·openharmony·适配·鸿蒙pc
Ai-_Man1 小时前
Coze扣子还是不可以导出左侧所有对话,只能点进去单条内容导出,方法不对吗?
开发语言·人工智能·ai·小程序·1024程序员节