旅行商问题(TSP)是一个经典的组合优化问题,也是计算机科学和运筹学中的一个重要问题。在TSP中,旅行商需要从一个城市出发,访问所有其他城市恰好一次,然后返回出发城市,使得所走过的路径总长度最短。这个问题在实际应用中非常常见,比如物流、电路板制作、DNA测序等领域都可以看到TSP的身影。TSP的难点在于随着城市数量的增加,搜索所有可能的路径将变得非常耗时,因为路径的数量是城市数量的阶乘。因此,寻找TSP的最优解是一个非常具有挑战性的任务,尤其是对于大规模问题。有许多算法被提出来解决TSP,包括暴力搜索、动态规划、遗传算法、蚁群算法、模拟退火等。这些算法各有优劣,适用于不同规模和特定类型的TSP问题。在这里我们采用模拟退火算法。
解题思路、方法实现:
模拟退火算法(Simulated Annealing)是一种启发式优化算法,受到固体退火过程的启发。该算法通过模拟物质在高温下退火冷却的过程,从而在解空间中跳出局部最优解,寻找全局最优解。
简单来说,模拟退火算法的主要步骤包括:
1 初始化:随机选择一个初始解,并设定初始温度(Temperature)。
2 循环迭代:在当前解的基础上进行微小的扰动,生成一个新解。计算新解的目标函数值(或者称为能量值)和当前解的目标函数值的差异(ΔE)。如果 ΔE 小于0,即新解更优,接受新解。如果 ΔE 大于0,以一定的概率(由一个概率分布计算得出,通常是玻尔兹曼分布)接受新解。这个概率随着温度的降低而减小,但在开始时有较大的概率接受劣解,以便跳出局部最优解。
3 降低温度,通常按照某个固定的降温率进行。
4 终止条件:当温度降低到足够低(接近零)或者达到最大迭代次数时停止算法。最终的解即为所求解。
这种随机性和“接受劣解”的策略使得模拟退火算法有可能避免陷入局部最优解,同时在搜索空间中进行广泛的探索,从而找到更优的解。算法中的温度和接受劣解的概率是关键的参数,它们影响了算法的探索性能。
在TSP问题中,模拟退火算法在解决旅行商问题(TSP)时的思路是通过在解空间中进行随机游走,模拟“退火”过程中的分子在热系统中的运动。具体步骤如下:
1 初始化解:随机生成一个初始路径,表示旅行商依次访问城市的顺序。
2 设定初始温度:初始时,系统的“温度”很高,容许接受较差的解。初始温度的选择对算法的性能有影响,通常由问题的特性和经验决定。
3 迭代过程:在当前解的基础上进行微小的扰动,例如交换两个城市的顺序,得到一个新的解。计算新解的路径长度与当前解的路径长度之差(ΔE)。如果 ΔE 小于0,即新解更优,直接接受新解。如果 ΔE 大于0,以一定的概率(由温度和 ΔE 决定)接受新解。温度高时,概率较大,有较大可能性接受劣解;随着迭代进行,温度逐渐降低,接受劣解的概率减小,算法越来越趋向于选择更好的解。
4 降低温度:在每个迭代步骤后,通过一个降温策略减小温度。典型的降温策略是乘以一个小于1的因子。
5 终止条件:当温度降低到足够低(接近零)或者达到最大迭代次数时停止算法。此时,当前解即为所求解。
读取tsp文件和距离矩阵文件
我们这里采用的数据集和下列博客的数据集一样,这篇博客给出了不使用txt数据,自定义距离矩阵的代码
https://blog.csdn.net/qq_49370210/article/details/134609526
import random
import math
# 读取 .tsp 文件以获取元数据
def read_tsp_file(filename):
metadata = {}
with open(filename, 'r') as file:
lines = file.readlines()
for line in lines:
if line.startswith("DIMENSION"):
metadata["num_cities"] = int(line.split(":")[1])
# 可以根据需要解析其他元数据
return metadata
# 读取距离矩阵文件 .d
def read_distance_matrix(filename, num_cities):
with open(filename, 'r') as file:
lines = file.readlines()
# 解析距离矩阵
distance_matrix = []
for line in lines:
row = [int(dist) for dist in line.strip().split()]
distance_matrix.append(row)
return distance_matrix
# 计算路径长度
def calculate_path_length(path, distance_matrix):
total_distance = 0
for i in range(len(path) - 1):
total_distance += distance_matrix[path[i]][path[i + 1]]
total_distance += distance_matrix[path[-1]][path[0]] # 回到起始城市
return total_distance
# 模拟退火算法
def simulated_annealing(distance_matrix, initial_temperature, cooling_rate, num_iterations):
current_solution = random.sample(range(len(distance_matrix)), len(distance_matrix))
current_energy = calculate_path_length(current_solution, distance_matrix)
best_solution = current_solution
best_energy = current_energy
temperature = initial_temperature
for _ in range(num_iterations):
# 生成新解
new_solution = current_solution[:]
# 随机选择两个位置交换
i, j = random.sample(range(len(new_solution)), 2)
new_solution[i], new_solution[j] = new_solution[j], new_solution[i]
new_energy = calculate_path_length(new_solution, distance_matrix)
# 计算能量差
delta_energy = new_energy - current_energy
# 如果新解更优,或者以一定概率接受劣解
if delta_energy < 0 or random.random() < math.exp(-delta_energy / temperature):
current_solution = new_solution
current_energy = new_energy
# 更新最优解
if current_energy < best_energy:
best_solution = current_solution
best_energy = current_energy
# 降低温度
temperature *= (1 - cooling_rate)
return best_solution, best_energy
'''
if __name__ == "__main__":
num_cities = 5
custom_distance_matrix = np.array([
[0, 10, 20, 15, 30], # 城市0到其他城市的距离
[10, 0, 25, 20, 35], # 城市1到其他城市的距离
[20, 25, 0, 12, 28], # 城市2到其他城市的距离
[15, 20, 12, 0, 22], # 城市3到其他城市的距离
[30, 35, 28, 22, 0] # 城市4到其他城市的距离
])
initial_temperature = 1000 # 初始温度
cooling_rate = 0.003 # 冷却率
num_iterations = 1000000
distance_matrix = read_distance_matrix(custom_distance_matrix, num_cities)
best_path, best_distance = simulated_annealing(distance_matrix, initial_temperature, cooling_rate, num_iterations)
print("最短路径:", best_path)
print("最短距离:", best_distance)
'''
# 主程序
if __name__ == "__main__":
tsp_metadata = read_tsp_file("dantzig42.tsp")
initial_temperature = 1000 # 初始温度
cooling_rate = 0.003 # 冷却率
num_iterations = 1000000
#distance_matrix = read_distance_matrix("dantzig42_d.txt",42)
#不使用tsp文件
distance_matrix = read_distance_matrix("dantzig42_d.txt", tsp_metadata["num_cities"])
best_path, best_distance = simulated_annealing(distance_matrix, initial_temperature, cooling_rate, num_iterations)
print("最短路径:", best_path)
print("最短距离:", best_distance)
111