鱼C论坛

 找回密码
 立即注册
查看: 374|回复: 3

[技术交流] Python遗传算法解TSP

[复制链接]
发表于 2024-10-11 20:08:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
专业选修课人工智能概论讲了遗传算法(GA),老师说让我们做一下遗传算法解TSP,刚好暑假搞数学建模学了点遗传算法,代码嘛,套着GA的模版改一改,就可以解TSP了
首先简单介绍一下遗传算法解TSP的基本思路:

  • 初始化:随机生成一定数量的个体(路径序列),每个个体表示一条旅行路线。
  • 适应度评估:计算每条路径的总距离,将距离转化为适应度值(适应度与路径长度成反比)。
  • 选择:通过轮盘赌选择或其他选择机制,选择适应度较高的个体进入下一代。
  • 交叉:随机选择一对个体,并在其路径中交叉生成新个体。
  • 变异:随机选择个体并在其路径中交换城市,以增加多样性。
  • 迭代:重复进行评估、选择、交叉和变异,直到达到指定代数或收敛条件。
  • 输出结果:返回适应度最高的路径及其长度。


  1. import random
  2. import math
  3. import numpy as np
  4. import time

  5. # 相关的系数
  6. PC = 0.55  # 交叉概率
  7. PM = 0.05   # 变异概率
  8. POP_SIZE = 100  # 种群规模
  9. N_GENERATIONS = 700  # 进化代数
  10. N_CITIES = 31  # 城市数量
  11. SEED = 20  # 随机种子

  12. # 城市坐标
  13. city_pos = [
  14.     [1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535],
  15.     [3326, 1556], [3238, 1229], [4196, 1004], [4312, 790], [4386, 570],
  16.     [3007, 1970], [2562, 1756], [2788, 1491], [2381, 1676], [1332, 695],
  17.     [3715, 1678], [3918, 2179], [4061, 2370], [3780, 2212], [3676, 2578],
  18.     [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2367], [3394, 2643],
  19.     [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826],
  20.     [2370, 2975]
  21. ]

  22. # 定义个体类
  23. class Individual:
  24.     def __init__(self, sequence):
  25.         self.sequence = sequence  # 城市访问序列
  26.         self.fitness = 0  # 适应度
  27.         self.p_fitness = 0  # 适应度概率
  28.         self.sum_p_fitness = 0  # 累加适应度概率

  29.     # 计算路径的适应度
  30.     def calculate_fitness(self):
  31.         total_distance = 0  # 总的距离
  32.         for i in range(N_CITIES):
  33.             city1 = self.sequence[i]
  34.             city2 = self.sequence[(i + 1) % N_CITIES]  # 回到起始城市
  35.             total_distance += self.calculate_distance(city1, city2)
  36.         self.fitness = 50000 - total_distance  # 适应度越高越好

  37.     # 计算两个城市之间的距离
  38.     @staticmethod
  39.     def calculate_distance(city1, city2):
  40.         x1, y1 = city_pos[city1 - 1]
  41.         x2, y2 = city_pos[city2 - 1]
  42.         return math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)

  43. # 初始化种群
  44. def initialize_population():
  45.     population = []
  46.     for _ in range(POP_SIZE):
  47.         sequence = list(range(1, N_CITIES + 1))
  48.         random.shuffle(sequence)  # 随机打乱城市顺序
  49.         individual = Individual(sequence)
  50.         population.append(individual)
  51.     return population

  52. # 计算适应度
  53. def calculate_fitness(population):
  54.     for individual in population:
  55.         individual.calculate_fitness()

  56. # 选择操作
  57. def selection(population):
  58.     population.sort(key=lambda ind: ind.fitness, reverse=True)  # 按适应度排序
  59.     selected = population[:POP_SIZE // 4]  # 选择适应度前 25% 的个体
  60.     # 轮盘选择
  61.     fitness_sum = sum(ind.fitness for ind in population)
  62.     probabilities = [ind.fitness / fitness_sum for ind in population]
  63.     cumulative_probabilities = np.cumsum(probabilities)
  64.     while len(selected) < POP_SIZE:
  65.         r = random.random()
  66.         for i, cum_prob in enumerate(cumulative_probabilities):
  67.             if r <= cum_prob:
  68.                 selected.append(population[i])
  69.                 break
  70.     return selected

  71. # 交叉操作
  72. def crossover(selected):
  73.     next_population = []
  74.     while len(next_population) < POP_SIZE:
  75.         parent1, parent2 = random.sample(selected, 2)
  76.         if random.random() <= PC:  # 按照交叉概率进行交叉
  77.             cross_point = random.randint(1, N_CITIES - 1)
  78.             child1_sequence = parent1.sequence[:cross_point] + \
  79.                               [city for city in parent2.sequence if city not in parent1.sequence[:cross_point]]
  80.             child2_sequence = parent2.sequence[:cross_point] + \
  81.                               [city for city in parent1.sequence if city not in parent2.sequence[:cross_point]]
  82.             next_population.append(Individual(child1_sequence))
  83.             next_population.append(Individual(child2_sequence))
  84.         else:
  85.             next_population.append(Individual(parent1.sequence))
  86.             next_population.append(Individual(parent2.sequence))
  87.     return next_population

  88. # 变异操作
  89. def mutation(population):
  90.     for individual in population:
  91.         if random.random() <= PM:  # 按照变异概率进行变异
  92.             idx1, idx2 = random.sample(range(N_CITIES), 2)  # 随机选择两个城市进行交换
  93.             individual.sequence[idx1], individual.sequence[idx2] = individual.sequence[idx2], individual.sequence[idx1]

  94. # 遗传算法主函数
  95. def genetic_algorithm():
  96.     population = initialize_population()  # 初始化种群
  97.     max_fitness_history = []  # 记录每代的最大适应度

  98.     for generation in range(N_GENERATIONS):
  99.         calculate_fitness(population)  # 计算适应度
  100.         max_fitness = max(ind.fitness for ind in population)  # 找到最大适应度
  101.         max_fitness_history.append(max_fitness)
  102.         print(f"代数: {generation}, 最大适应度: {max_fitness}")

  103.         selected = selection(population)  # 选择
  104.         next_population = crossover(selected)  # 交叉
  105.         mutation(next_population)  # 变异
  106.         population = next_population  # 更新种群

  107.     # 输出结果
  108.     best_individual = max(population, key=lambda ind: ind.fitness)
  109.     print("最佳路径:", "->".join(map(str, best_individual.sequence)))
  110.     print("路径长度:", 50000 - best_individual.fitness)

  111. if __name__ == "__main__":
  112.     start_time = time.time()
  113.     genetic_algorithm()
  114.     print("总时间:", time.time() - start_time, "秒")
复制代码


屏幕截图 2024-10-11 200055.png



小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-10-11 20:10:03 | 显示全部楼层
杂交的方式,轮盘赌,还有变异,这些可以自己调,可以有自己的规则,还有编码方式,适应度的计算函数,都可以改
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-11 20:09:05 | 显示全部楼层
遗传算法解决TSP问题的代码实现中,你已经提供了一个基本的框架。以下是一些需要补充和修正的地方:

1. **城市坐标**:需要填充`city_pos`列表,确保每个城市都有一个(x, y)坐标。

2. **个体类的路径计算**:在`calculate_fitness`方法中,`city1`和`city2`的索引需要正确设置。

3. **初始化种群**:`initialize_population`函数中需要初始化`population`列表。

4. **选择操作**:在`selection`函数中,`probabilities`需要计算每个个体的选择概率。

以下是修正后的代码片段:

  1. # 城市坐标示例
  2. city_pos = [
  3.     (0, 0), (1, 1), (2, 2), (3, 3), (4, 4),
  4.     (5, 5), (6, 6), (7, 7), (8, 8), (9, 9),
  5.     (10, 10), (11, 11), (12, 12), (13, 13), (14, 14),
  6.     (15, 15), (16, 16), (17, 17), (18, 18), (19, 19),
  7.     (20, 20), (21, 21), (22, 22), (23, 23), (24, 24),
  8.     (25, 25), (26, 26), (27, 27), (28, 28), (29, 29),
  9.     (30, 30)
  10. ]

  11. # 计算路径的适应度
  12. def calculate_fitness(self):
  13.     total_distance = 0
  14.     for i in range(N_CITIES):
  15.         city1 = self.sequence[i]
  16.         city2 = self.sequence[(i + 1) % N_CITIES]  # 回到起始城市
  17.         total_distance += self.calculate_distance(city1, city2)
  18.     self.fitness = 50000 - total_distance

  19. # 初始化种群
  20. def initialize_population():
  21.     population = []
  22.     for _ in range(POP_SIZE):
  23.         sequence = list(range(N_CITIES))
  24.         random.shuffle(sequence)
  25.         individual = Individual(sequence)
  26.         population.append(individual)
  27.     return population

  28. # 选择操作
  29. def selection(population):
  30.     population.sort(key=lambda ind: ind.fitness, reverse=True)
  31.     selected = population[:int(0.25 * POP_SIZE)]
  32.     fitness_sum = sum(ind.fitness for ind in population)
  33.     probabilities = [ind.fitness / fitness_sum for ind in population]
  34.     cumulative_probabilities = np.cumsum(probabilities)
  35.     while len(selected) < POP_SIZE:
  36.         r = random.random()
  37.         for i, cum_prob in enumerate(cumulative_probabilities):
  38.             if r < cum_prob:
  39.                 selected.append(population[i])
  40.                 break
  41.     return selected
复制代码


请根据你的具体需求和城市坐标进行调整。希望这些修改能帮助你更好地实现遗传算法解决TSP问题!如果有其他问题,欢迎继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-10-11 20:10:37 | 显示全部楼层
yinda_peng 发表于 2024-10-11 20:10
杂交的方式,轮盘赌,还有变异,这些可以自己调,可以 ...


要实现遗传算法解决TSP问题,你可以根据自己的需求调整杂交、选择和变异的方式。以下是一些建议和代码补充:

### 杂交(交叉)

常用的杂交方法有部分映射交叉(PMX)、顺序交叉(OX)等。你可以选择其中一种或自己设计。

### 轮盘赌选择

轮盘赌选择是根据适应度概率选择个体。你需要计算每个个体的适应度概率,并使用累积概率进行选择。

### 变异

变异可以通过交换路径中的两个城市来实现,以增加种群的多样性。

### 代码补充

以下是对你提供的代码的补充和修正:

  1. # 初始化种群
  2. def initialize_population():
  3.     population = []
  4.     for _ in range(POP_SIZE):
  5.         sequence = list(range(N_CITIES))
  6.         random.shuffle(sequence)  # 随机打乱城市顺序
  7.         individual = Individual(sequence)
  8.         population.append(individual)
  9.     return population

  10. # 计算适应度
  11. def calculate_fitness(population):
  12.     for individual in population:
  13.         individual.calculate_fitness()

  14. # 选择操作
  15. def selection(population):
  16.     population.sort(key=lambda ind: ind.fitness, reverse=True)  # 按适应度排序
  17.     selected = population[:POP_SIZE // 4]  # 选择适应度前 25% 的个体
  18.     # 轮盘选择
  19.     fitness_sum = sum(ind.fitness for ind in population)
  20.     probabilities = [ind.fitness / fitness_sum for ind in population]
  21.     cumulative_probabilities = np.cumsum(probabilities)
  22.     while len(selected) < POP_SIZE:
  23.         r = random.random()
  24.         for i, cum_prob in enumerate(cumulative_probabilities):
  25.             if r < cum_prob:
  26.                 selected.append(population[i])
  27.                 break
  28.     return selected

  29. # 交叉操作
  30. def crossover(parent1, parent2):
  31.     # 这里可以实现PMX或OX等交叉方法
  32.     pass

  33. # 变异操作
  34. def mutate(individual):
  35.     if random.random() < PM:
  36.         idx1, idx2 = random.sample(range(N_CITIES), 2)
  37.         individual.sequence[idx1], individual.sequence[idx2] = individual.sequence[idx2], individual.sequence[idx1]
复制代码


### 说明

- **初始化种群**:生成随机路径序列。
- **适应度计算**:根据路径总距离计算适应度。
- **选择**:使用轮盘赌选择适应度高的个体。
- **交叉和变异**:实现交叉和变异以生成新个体。

你可以根据需要调整这些方法的实现细节。希望这些信息对你有帮助!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-19 22:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表