yinda_peng 发表于 2024-10-11 20:08:32

Python遗传算法解TSP

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

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


import random
import math
import numpy as np
import time

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

# 城市坐标
city_pos = [
    , , , , ,
    , , , , ,
    , , , , ,
    , , , , ,
    , , , , ,
    , , , , ,
   
]

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

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

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

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

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

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

# 交叉操作
def crossover(selected):
    next_population = []
    while len(next_population) < POP_SIZE:
      parent1, parent2 = random.sample(selected, 2)
      if random.random() <= PC:# 按照交叉概率进行交叉
            cross_point = random.randint(1, N_CITIES - 1)
            child1_sequence = parent1.sequence[:cross_point] + \
                              ]
            child2_sequence = parent2.sequence[:cross_point] + \
                              ]
            next_population.append(Individual(child1_sequence))
            next_population.append(Individual(child2_sequence))
      else:
            next_population.append(Individual(parent1.sequence))
            next_population.append(Individual(parent2.sequence))
    return next_population

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

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

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

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

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

if __name__ == "__main__":
    start_time = time.time()
    genetic_algorithm()
    print("总时间:", time.time() - start_time, "秒")




yinda_peng 发表于 2024-10-11 20:10:03

杂交的方式,轮盘赌,还有变异,这些可以自己调,可以有自己的规则,还有编码方式,适应度的计算函数,都可以改

FishC 发表于 2024-10-11 20:09:05

遗传算法解决TSP问题的代码实现中,你已经提供了一个基本的框架。以下是一些需要补充和修正的地方:

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

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

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

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

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

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

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

# 初始化种群
def initialize_population():
    population = []
    for _ in range(POP_SIZE):
      sequence = list(range(N_CITIES))
      random.shuffle(sequence)
      individual = Individual(sequence)
      population.append(individual)
    return population

# 选择操作
def selection(population):
    population.sort(key=lambda ind: ind.fitness, reverse=True)
    selected = population[:int(0.25 * POP_SIZE)]
    fitness_sum = sum(ind.fitness for ind in population)
    probabilities =
    cumulative_probabilities = np.cumsum(probabilities)
    while len(selected) < POP_SIZE:
      r = random.random()
      for i, cum_prob in enumerate(cumulative_probabilities):
            if r < cum_prob:
                selected.append(population)
                break
    return selected

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

FishC 发表于 2024-10-11 20:10:37

yinda_peng 发表于 2024-10-11 20:10
杂交的方式,轮盘赌,还有变异,这些可以自己调,可以 ...

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

### 杂交(交叉)

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

### 轮盘赌选择

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

### 变异

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

### 代码补充

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

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

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

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

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

# 变异操作
def mutate(individual):
    if random.random() < PM:
      idx1, idx2 = random.sample(range(N_CITIES), 2)
      individual.sequence, individual.sequence = individual.sequence, individual.sequence

### 说明

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: Python遗传算法解TSP