TSP 遗传算法 代码实现

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)
posted @ 2025-03-07 22:40  ToFuture$  阅读(47)  评论(0)    收藏  举报