import random
import math
import matplotlib.pyplot as plt
# 遗传算法参数
POPULATION_SIZE = 100 # 种群大小
MUTATION_RATE = 0.02 # 变异概率
GENERATIONS = 500 # 迭代次数
TOURNAMENT_SIZE = 5 # 锦标赛选择时的竞争个体数
class TSPGeneticAlgorithm:
def __init__(self, cities):
"""
初始化 TSP 遗传算法
:param cities: 城市坐标列表,格式如 [(x1, y1), (x2, y2), ...]
"""
self.cities = cities
self.population = []
self.best_distance = float('inf')
self.best_route = []
# 预计算城市间距离矩阵(提升性能)
self.dist_matrix = self.precompute_distance_matrix()
def precompute_distance_matrix(self):
"""计算所有城市间的欧氏距离,存储为矩阵"""
n = len(self.cities)
matrix = [[0.0] * n for _ in range(n)]
for i in range(n):
for j in range(i + 1, n):
dx = self.cities[i][0] - self.cities[j][0]
dy = self.cities[i][1] - self.cities[j][1]
matrix[i][j] = matrix[j][i] = math.hypot(dx, dy) # 欧氏距离
return matrix
def initialize_population(self):
"""生成初始种群:每个个体是一个随机排列的路径"""
city_indices = list(range(len(self.cities)))
self.population = [random.sample(city_indices, len(city_indices))
for _ in range(POPULATION_SIZE)]
def calculate_route_distance(self, route):
"""计算一条路径的总距离"""
total = 0.0
for i in range(len(route)):
current_city = route[i]
next_city = route[(i + 1) % len(route)]
total += self.dist_matrix[current_city][next_city]
return total
def tournament_selection(self):
"""锦标赛选择:每次随机选 TOURNAMENT_SIZE 个个体,取最优的"""
selected = []
for _ in range(POPULATION_SIZE):
candidates = random.sample(self.population, TOURNAMENT_SIZE)
best_candidate = min(candidates, key=lambda x: self.calculate_route_distance(x))
selected.append(best_candidate.copy())
return selected
def order_crossover(self, parent1, parent2):
"""
顺序交叉 (OX):保留 parent1 的一个子序列,按 parent2 的顺序填充剩余城市
示例:
Parent1: [A, B, C, D, E, F]
Parent2: [D, E, A, B, F, C]
子序列: B, C, D → Child: [E, A, B, C, D, F]
"""
size = len(parent1)
start, end = sorted([random.randint(0, size - 1), random.randint(0, size - 1)])
# 从 parent1 复制子序列
child = [None] * size
child[start:end + 1] = parent1[start:end + 1]
# 从 parent2 填充剩余城市
ptr = 0
for city in parent2:
if city not in child[start:end + 1]:
if ptr >= size:
break
while child[ptr] is not None:
ptr += 1
child[ptr] = city
ptr += 1
return child
def mutate(self, route):
"""交换变异:随机选择两个位置交换"""
if random.random() < MUTATION_RATE:
i, j = random.sample(range(len(route)), 2)
route[i], route[j] = route[j], route[i]
return route
def evolve(self):
"""执行遗传算法进化"""
self.initialize_population()
for gen in range(GENERATIONS):
# 计算当前种群的最优解
current_best = min(self.population, key=lambda x: self.calculate_route_distance(x))
current_distance = self.calculate_route_distance(current_best)
# 更新全局最优
if current_distance < self.best_distance:
self.best_distance = current_distance
self.best_route = current_best.copy()
print(f"Generation {gen}: New best distance = {self.best_distance:.2f}")
# 选择
selected = self.tournament_selection()
# 交叉生成新种群
new_population = []
for i in range(0, POPULATION_SIZE, 2):
parent1 = selected[i]
parent2 = selected[i + 1] if (i + 1) < POPULATION_SIZE else selected[0]
# 生成两个子代
child1 = self.order_crossover(parent1, parent2)
child2 = self.order_crossover(parent2, parent1)
# 变异
child1 = self.mutate(child1)
child2 = self.mutate(child2)
new_population.extend([child1, child2])
# 更新种群
self.population = new_population[:POPULATION_SIZE]
def plot_route(self, route):
"""绘制路径图"""
x = [self.cities[i][0] for i in route] + [self.cities[route[0]][0]]
y = [self.cities[i][1] for i in route] + [self.cities[route[0]][1]]
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'o-', linewidth=1, markersize=8)
plt.title(f"TSP Route - Total Distance: {self.best_distance:.2f}")
plt.xlabel("X Coordinate")
plt.ylabel("Y Coordinate")
plt.grid(True)
plt.show()
# 测试用例:随机生成20个城市坐标
random.seed(42) # 固定随机种子,确保结果可复现
cities = [(random.uniform(0, 100), random.uniform(0, 100)) for _ in range(20)]
# 运行算法
tsp_solver = TSPGeneticAlgorithm(cities)
tsp_solver.evolve()
# 输出结果
print("\n=== Optimal Route ===")
print(f"Best Distance: {tsp_solver.best_distance:.2f}")
print("Route Order:", tsp_solver.best_route)
# 绘制路径图
tsp_solver.plot_route(tsp_solver.best_route)