模拟退火算法解决TSP问题

 作者:邬杨明
1
# 模拟退火算法求解三十城市TSP问题 2 # 2018-3-21 3 # yangmingustb@outlook.com 4 5 6 import math 7 import random 8 import datetime 9 import copy 10 import matplotlib.pyplot as plt 11 12 13 class SaTSP(object): 14 15 def __init__(self, tf=0.01, alpha=0.9): 16 self.tf = tf # 最低温度 17 self.alpha = alpha # 降温系数 18 self.iter_num = [] # 记录迭代次数 19 self.distance_path = [] # 记录每一步迭代出来的路径长度 20 self.ultimate_path = [] 21 # 30城市坐标 22 self.coordinates = [[41, 94], [37, 84], [54, 67], [25, 62], [7, 64], 23 [2, 99], [68, 58], [71, 44], [54, 62], [83, 69], 24 [64, 60], [18, 54], [22, 60], [83, 46], [91, 38], 25 [25, 38], [24, 42], [58, 69], [71, 71], [74, 78], 26 [87, 76], [18, 40], [13, 40], [82, 7], [62, 32], 27 [58, 35], [45, 21], [41, 26], [44, 35], [4, 50] 28 ] 29 30 self.iteration = 200 * len(self.coordinates) # 每一个温度过程中迭代次数,马氏链长度 31 32 def initial_temperature(self): # 温度初始化,采用t0=-delta(f)/(ln0.9) 33 34 dist_list = [] 35 for i in range(100): # 生成一百条路径 36 37 path = random.sample(self.coordinates, len(self.coordinates)) # 生成一条随机序列 38 dist_list.append(self.all_dist(path)) 39 40 t0 = -(max(dist_list) - min(dist_list)) / math.log(0.9) # 设置初温 41 print('初始温度是:', t0) 42 return t0 43 44 def D_value(self, current_path, update_path): # 变换前后目标函数差值 45 46 # print('计算两个状态的差值...') 47 current_distance = self.all_dist(current_path) 48 # print('当前距离', current_distance) 49 50 update_distance = self.all_dist(update_path) 51 # print(update_distance) 52 53 d_value = update_distance - current_distance 54 return d_value 55 56 def first_path(self): # 生成第一条初始化的路径 57 length = len(self.coordinates) 58 # 因为对初值不敏感,生成一条随机序列, 第一条路径是随机的 59 path = random.sample(self.coordinates, length) 60 return path 61 62 # 随机交换2个城市顺序,这一步非常重要,调试了五个小时一直不收敛, 63 # 深入理解深拷贝和浅拷贝的区别,注意内存中的变化 64 def swap(self, path): 65 # print('产生新解...') 66 city_1 = random.randint(1, len(self.coordinates) - 1) # 产生第一个交换点 67 while True: 68 city_2 = random.randint(1, len(self.coordinates) - 1) # 产生第二个交换点 69 if city_2 != city_1: 70 break 71 else: 72 continue 73 path[city_1], path[city_2] = path[city_2], path[city_1] 74 # print('产生新解结束') 75 return path 76 77 # 计算两个点之间的距离 78 def two_point_dist(self, point1, point2): 79 80 dist_x = point1[0] - point2[0] 81 dist_y = point1[1] - point2[1] 82 dist = dist_x ** 2 + dist_y ** 2 83 dist = math.sqrt(dist) 84 return dist 85 86 def all_dist(self, path): # 计算所有点距离,总共30段距离 87 sum_cities = 0 88 n = len(path) 89 for i in range(n - 1): # 先计算前29段距离 90 sum_cities += self.two_point_dist(path[i], path[i + 1]) 91 sum_cities += self.two_point_dist(path[n - 1], path[0]) # 计算第30个点和第一个点的距离,形成闭环 92 return sum_cities 93 94 def city_scatter(self): # 画出城市分布散点图 95 city_x = [] 96 city_y = [] 97 for i in self.coordinates: 98 city_x.append(i[0]) 99 city_y.append(i[1]) 100 plt.scatter(city_x, city_y) 101 plt.show() 102 103 def city_plot(self, path): # 画出最终路径图 104 city_x = [] 105 city_y = [] 106 for i in path: 107 city_x.append(i[0]) 108 city_y.append(i[1]) 109 plt.plot(city_x, city_y) 110 plt.show() 111 112 def plot_graphic(self): # 画出路径长度随迭代次数变化曲线图 113 plt.plot(self.iter_num, self.distance_path) 114 plt.show() 115 116 def main(self): # 函数式编程,调用其它函数,进入这个大循环 117 118 start_time = datetime.datetime.now() # 增加时间模块,计算运行时间 119 t = self.initial_temperature() # 调用生成初温函数 120 current_path = self.first_path() 121 # print(current_path) 122 i = 0 123 while t > self.tf: # 终止条件 124 iteration_number = 0 125 while iteration_number < self.iteration: # metropolis终止条件 126 # a = self.all_dist(current_path) 127 temple_path = copy.deepcopy(current_path) # 建立一个当前路径临时列表,防止改变当前路径值 128 update_path = self.swap(temple_path) 129 # print(update_path) 130 de2 = self.D_value(current_path, update_path) 131 # print(de,de2) 132 133 if de2 < 0: # 如果增量为负值,则接受 134 135 current_path = update_path 136 # print(current_path) 137 138 else: # 产生新解比较 139 p = math.exp(-de2 / t) 140 if random.random() <= p: 141 current_path = update_path 142 # print(current_path) 143 144 else: # 否则保留当前解解,而不是一直产生新解比较,注意误区 145 current_path = current_path 146 # else: 147 iteration_number += 1 148 149 t = self.alpha * t 150 151 i = i + 1 152 self.iter_num.append(i) 153 self.ultimate_path = current_path 154 distance = self.all_dist(current_path) 155 self.distance_path.append(distance) # 路径长度存入列表 156 # print(distance) 157 158 end_time = datetime.datetime.now() 159 this_time = end_time - start_time 160 print('程序运行时间:', this_time) 161 162 self.city_scatter() 163 self.city_plot(self.ultimate_path) 164 165 166 s1 = SaTSP() 167 168 s1.main()


原文地址:https://www.cnblogs.com/yangmingustb/p/8641124.html