设计思路:
程序清单:
文件名 | 定位 | 作用 |
cities.json | json数据 | 存储城市坐标信息 |
tool.py | 工具模块 | 提供读取JSON数据、生成随机点、生成距离矩阵等函数 |
main.py | 主模块 | 程序入口,求解TSP问题并可视化 |
cities.json:json数据
[[88, 88], [93, 13], [17, 20], [13, 70]]
tool.py:工具模块
# -*- coding:utf-8 -*-
import math
import json
import random
# 生成一定范围的随机数
def random_double(_min, _max):
return random.random() * (_max - _min) + _min
# 生成随机城市坐标
def random_cities(_min, _max, num):
return [[random_double(_min, _max), random_double(_min, _max)] for _ in range(num)]
# 计算欧式距离
def distance(c1, c2):
return math.sqrt(square_distance(c1, c2))
# 计算平方欧式距离
def square_distance(c1, c2):
return (c1[0] - c2[0]) ** 2 + (c1[1] - c2[1]) ** 2
# 由城市坐标列表,生成距离矩阵
def distance_matrix(_cities):
length = len(_cities)
matrix = [[-1.0] * length for _ in range(length)]
for i in range(length - 1):
for j in range(i + 1, length):
matrix[i][j] = matrix[j][i] = distance(_cities[i], _cities[j])
return matrix
# 从json文件中,读取城市信息
def read_cities():
json_path = 'cities.json'
with open(json_path, 'r') as f:
return json.load(f)
main.py:主模块
# -*- coding:utf-8 -*-
from tool import read_cities, distance_matrix
import matplotlib.pyplot as plt
class Solution:
def __init__(self, _matrix, start_node):
# 距离矩阵
self.matrix = _matrix
# 节点数目
self.height = len(self.matrix)
# 宽度
self.width = 2 ** self.height
# 开始节点
self.start_node = start_node
# 记录处于x节点,未经历M个节点时
# 矩阵储存x的下一步是M中哪个节点
self.array = [[0] * self.width for _ in range(self.height)]
def tsp(self):
# 开始节点
s = self.start_node
# 节点数目
num = self.height
# 未遍历节点集合
_cities = list(range(num))
_cities.pop(s)
# 求解函数
return self.solve(s, _cities)
@staticmethod
def transfer(sets):
_sum = 0
for s in sets:
_sum += 2 ** s # 二进制转换
return _sum
def solve(self, node, future_sets):
# 迭代终止条件,
# 表示没有了未遍历节点,直接连接当前节点和起点即可
if len(future_sets) == 0:
return self.matrix[node][self.start_node]
# node如果经过future_sets中节点,最后回到原点的距离
distance = []
# 遍历未经历的节点
for i in range(len(future_sets)):
s_i = future_sets[i]
# 访问s_i,更新当前未访问节点集合
copy = future_sets[:]
copy.pop(i)
# 递归,动态规划递推方程
distance.append(self.matrix[node][s_i] + self.solve(s_i, copy))
# 最小距离
d = min(distance)
# node需要连接的下一个节点
next_one = future_sets[distance.index(d)]
# 未遍历节点集合
c = self.transfer(future_sets)
# (当前节点,未遍历节点集合)-->下一个节点
self.array[node][c] = next_one
return d
if __name__ == '__main__':
# 从JSON读取数据
cities = read_cities()
# 生成距离矩阵
mat = distance_matrix(cities)
# 调用tsp
S = Solution(mat, 0)
S.tsp()
# 开始回溯
lists = list(range(len(S.matrix)))
start_node = S.start_node
# 生成路径
output_path = list()
while len(lists) > 0:
lists.pop(lists.index(start_node))
# 未访问节点集合 矩阵中的y坐标
y = S.transfer(lists)
# 下一节点
next_node = S.array[start_node][y]
# 添加下一组合
output_path.append([start_node, next_node])
# 从下一节点出发
start_node = next_node
# 输出城市列表
print('城市坐标集合为:')
for city in cities:
print(city, end=' ')
print()
# 距离矩阵
print('距离矩阵为:')
for row in mat:
for col in row:
print('%10.2f' % col, end=' ')
print()
# 输出路径
print('最优路径为:')
for i in output_path:
print(i[0], '-->', end='')
print('0')
# 画散点图
i = 0
for city in cities:
plt.scatter(city[0], city[1])
plt.annotate("City%d(%d, %d)" % (i, city[0], city[1]), (city[0] + 2, city[1] + 2))
i += 1
# 画出路径
for start_node, next_node in output_path:
cs = cities[start_node]
cn = cities[next_node]
plt.plot([cs[0], cn[0]], [cs[1], cn[1]])
# 不显示坐标轴
plt.axis('off')
# 绘图
plt.show()
TSP问题
输出结果:
绘图结果: