Advertisement

模拟退火算法求解TSP问题

阅读量:

模拟退火算法(Simulated Annealing, SA)是一种典型的全局搜索优化方法,在处理具有复杂约束条件下的组合优化问题方面具有显著优势。例如旅行商问题(TSP),该算法旨在找到一条闭合回路路径,在满足所有城市节点必须被遍历且仅访问一次的前提下,并使总行程距离达到最小值。

模拟退火算法求解 TSP 问题的基本步骤:

初始化温度和初始解

首先随机初始化一个城市排列。
设置初始温度TTT并设定降温系数。
在每个迭代周期中执行以下步骤:
- 选择下一个候选解;
- 计算候选解的成本函数值;
- 比较新旧解的成本并决定是否接受新解;
- 根据当前温度计算接受概率;
- 根据设定的降温系数更新当前温度;
- 当达到终止条件时退出循环。

循环降温过程

  • 按照给定的温度 TTT 值,在给定的温度下进行若干次迭代。
  • 每一次迭代过程中,在当前解的基础上施加一次扰动(如随机互换两个城市的位置),从而生成新的解。

评价新解

  • 评估新解的总路径长度。
  • 求取能量差 \Delta E = E_{\text{new}} - E_{\text{old}}(基于两路径之间的总距离差异)。
  • 当能量差小于等于零时(即新路径更优),接受该新解。
  • 当能量差为正时,则按照概率 p = \exp(-\Delta E / T) 接受该新解;同时,在初始阶段时态与当前状态越接近时被接受的可能性越大。
    .

降低温度

在每一轮循环结束后通过降温公式对温度进行更新,并根据降温比值调整当前温度值。

终止条件

当温度降至设定的最小值以下或达到预先设定的最大循环次数时(T_{\text{min}}),该算法终止运行并输出当前找到的最优解

模拟退火算法代码示例 (Python)

复制代码
 import numpy as np

    
 import matplotlib.pyplot as plt
    
 import os
    
  
    
 class TSPSimulatedAnnealing:
    
     def __init__(self, filename, save_dir='results', initial_temperature=1000, min_temperature=1e-5, cooling_rate=0.999, max_iterations=100000000):
    
     self.coords = self.read_tsp_file(filename)
    
     self.distance_matrix = self.calculate_distance_matrix(self.coords)
    
     self.initial_temperature = initial_temperature
    
     self.min_temperature = min_temperature
    
     self.cooling_rate = cooling_rate
    
     self.max_iterations = max_iterations
    
     self.save_dir = save_dir
    
     os.makedirs(self.save_dir, exist_ok=True)
    
     
    
     def read_tsp_file(self, filename):
    
     """读取 TSP 文件并返回城市坐标列表"""
    
     coords = []
    
     with open(filename, 'r') as file:
    
         for line in file:
    
             if line.strip() == 'NODE_COORD_SECTION':
    
                 break
    
         for line in file:
    
             if line.strip() == 'EOF':
    
                 break
    
             parts = line.strip().split()
    
             coords.append((float(parts[1]), float(parts[2])))
    
     return np.array(coords)
    
     
    
     def calculate_distance_matrix(self, coords):
    
     """计算城市之间的欧几里得距离矩阵"""
    
     return np.sqrt(((coords[:, np.newaxis] - coords) ** 2).sum(axis=2))
    
  
    
     def calculate_total_distance(self, route):
    
     """计算给定路线的总距离"""
    
     return sum(self.distance_matrix[route[i - 1], route[i]] for i in range(len(route)))
    
  
    
     def perturbation(self, route):
    
     """使用反转区间法扰动生成新解"""
    
     new_route = np.copy(route)
    
     i, j = sorted(np.random.choice(len(route), 2, replace=False))
    
     new_route[i:j+1] = new_route[i:j+1][::-1]
    
     return new_route
    
  
    
     def simulated_annealing(self):
    
     """使用模拟退火算法求解 TSP 问题"""
    
     num_cities = len(self.distance_matrix)
    
     current_solution = np.arange(num_cities)
    
     np.random.shuffle(current_solution)
    
     current_distance = self.calculate_total_distance(current_solution)
    
     
    
     T = self.initial_temperature
    
     best_solution = np.copy(current_solution)
    
     best_distance = current_distance
    
     iteration = 0
    
     no_improve_count = 0
    
  
    
     while T > self.min_temperature and iteration < self.max_iterations:
    
         new_solution = self.perturbation(current_solution)
    
         new_distance = self.calculate_total_distance(new_solution)
    
  
    
         delta = new_distance - current_distance
    
         if delta < 0 or np.random.rand() < np.exp(-delta / T):
    
             current_solution = new_solution
    
             current_distance = new_distance
    
             no_improve_count = 0
    
             if current_distance < best_distance:
    
                 best_solution = np.copy(current_solution)
    
                 best_distance = current_distance
    
         else:
    
             no_improve_count += 1
    
  
    
         if no_improve_count > 500:
    
             T *= (self.cooling_rate + 0.001)
    
             no_improve_count = 0
    
         else:
    
             T *= self.cooling_rate
    
  
    
         iteration += 1
    
  
    
     # 保存最佳路径和最短距离
    
     self.save_results(best_solution, best_distance)
    
     return best_solution, best_distance
    
  
    
     def save_results(self, best_solution, best_distance):
    
     """保存最优路径、最短距离和图像"""
    
     # 保存路径数据
    
     with open(os.path.join(self.save_dir, 'best_path.txt'), 'w') as file:
    
         file.write("最优访问路径: " + ' '.join(map(lambda x: str(x + 1), best_solution)) + "\n")
    
         file.write(f"最短总距离: {best_distance}\n")
    
     
    
     # 保存路径图
    
     self.plot_path(best_solution, os.path.join(self.save_dir, 'best_path.png'))
    
  
    
     def plot_path(self, path, save_path=None):
    
     """绘制城市及其路径并保存图像"""
    
     city_coords = self.coords
    
     plt.figure(figsize=(20, 15))
    
     
    
     path = np.append(path, path[0])
    
     x = [city_coords[i][0] for i in path]
    
     y = [city_coords[i][1] for i in path]
    
     
    
     plt.plot(x, y, linestyle='--', linewidth=2, markersize=10, color='red')
    
     plt.plot(x, y, marker='o', markersize=10, linewidth=0, color='black')
    
  
    
     for idx, i in enumerate(path[:-1]):
    
         if idx == 0:
    
             plt.text(city_coords[i][0], city_coords[i][1], str(i + 1), fontsize=20, ha='right', color='red')
    
         else:
    
             plt.text(city_coords[i][0], city_coords[i][1], str(i + 1), fontsize=15, ha='right')
    
     
    
     plt.title('SA_TSP Optimal Path', fontsize=20)
    
     plt.xlabel('X ', fontsize=20)
    
     plt.ylabel('Y ', fontsize=20)
    
     plt.xticks(fontsize=20)
    
     plt.yticks(fontsize=20)  
    
     plt.grid(True)
    
  
    
     if save_path:
    
         plt.savefig(save_path)
    
     plt.close()
    
  
    
 # 示例
    
 filename = 'kroB100.tsp'
    
 solver = TSPSimulatedAnnealing(filename)
    
 best_solution, best_distance = solver.simulated_annealing()
    
  
    
 print("最佳路径:", best_solution)
    
 print("最短距离:", best_distance)
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/6piyS1rcXR3jx0AD2hKPbHO4Bsnl.png)

全部评论 (0)

还没有任何评论哟~