遗传算法实战:5分钟用Python解决背包问题(附完整代码)

张开发
2026/4/21 11:21:18 15 分钟阅读

分享文章

遗传算法实战:5分钟用Python解决背包问题(附完整代码)
遗传算法实战5分钟用Python解决背包问题附完整代码背包问题一直是计算机科学中的经典难题它模拟了我们在有限资源下如何做出最优选择的场景。想象一下你正在准备一次徒步旅行背包容量有限但想带的物品却很多——食物、水、帐篷、相机等等。每件物品都有不同的重量和价值如何选择才能在不超过背包承重的前提下带走最有价值的物品组合这就是背包问题的现实映射。遗传算法(Genetic Algorithm, GA)作为一种受生物进化启发的优化方法特别适合解决这类组合优化问题。与传统暴力搜索不同GA通过模拟自然选择的过程能够在合理时间内找到近似最优解。本文将带你用Python快速实现一个遗传算法解决0-1背包问题。即使你是GA新手也能在5分钟内理解核心概念并运行完整代码。1. 遗传算法核心概念速成遗传算法的灵感来源于达尔文的自然选择理论。它通过以下生物学术语与计算概念的对应构建了一套完整的优化框架染色体(Chromosome): 在GA中代表一个潜在解通常用二进制串表示。对于背包问题染色体可以表示为一个二进制序列其中每一位代表是否选择对应物品。种群(Population): 一组染色体的集合代表当前一代的所有潜在解。适应度函数(Fitness Function): 评估染色体优劣的标准。背包问题中适应度可以是所选物品的总价值需满足重量约束。选择(Selection): 模拟适者生存优先选择适应度高的染色体参与繁殖。常用方法包括轮盘赌选择锦标赛选择精英保留策略交叉(Crossover): 两个父代染色体交换部分基因产生新个体。这是GA探索新解的主要方式。变异(Mutation): 以较小概率随机改变某些基因位增加种群多样性避免早熟收敛。# 伪代码展示GA基本流程 population 初始化种群() while 不满足终止条件: 评估种群中每个个体的适应度() 新种群 [] for i in range(种群大小//2): 父代1 选择个体(种群) 父代2 选择个体(种群) 子代1, 子代2 交叉(父代1, 父代2) 子代1 变异(子代1) 子代2 变异(子代2) 新种群.extend([子代1, 子代2]) population 新种群2. 背包问题的Python实现让我们用Python实现一个具体的0-1背包问题。假设背包最大承重为15kg有以下物品可供选择物品重量(kg)价值A110B25C315D420E5252.1 问题编码与初始化首先定义问题参数和染色体表示import random # 背包问题参数 items [ {name: A, weight: 1, value: 10}, {name: B, weight: 2, value: 5}, {name: C, weight: 3, value: 15}, {name: D, weight: 4, value: 20}, {name: E, weight: 5, value: 25} ] max_weight 15 # 背包最大承重 population_size 50 # 种群大小 chromosome_length len(items) # 染色体长度(物品数量)初始化种群函数def initialize_population(): population [] for _ in range(population_size): chromosome [random.randint(0, 1) for _ in range(chromosome_length)] population.append(chromosome) return population2.2 适应度函数设计适应度函数需要同时考虑总价值和重量约束。对于违反约束的解我们给予惩罚def calculate_fitness(chromosome): total_value 0 total_weight 0 for i in range(chromosome_length): if chromosome[i] 1: total_value items[i][value] total_weight items[i][weight] # 惩罚超出重量的解 if total_weight max_weight: total_value max(0, total_value - 10 * (total_weight - max_weight)) return total_value2.3 选择操作实现这里实现锦标赛选择它比轮盘赌选择更不容易陷入局部最优def tournament_selection(population, fitnesses, tournament_size3): selected [] for _ in range(len(population)): contestants random.sample(list(zip(population, fitnesses)), tournament_size) winner max(contestants, keylambda x: x[1])[0] selected.append(winner) return selected2.4 交叉与变异操作单点交叉和基本位变异实现def crossover(parent1, parent2, crossover_rate0.8): if random.random() crossover_rate: point random.randint(1, chromosome_length - 1) child1 parent1[:point] parent2[point:] child2 parent2[:point] parent1[point:] return child1, child2 return parent1, parent2 def mutate(chromosome, mutation_rate0.05): for i in range(len(chromosome)): if random.random() mutation_rate: chromosome[i] 1 - chromosome[i] # 翻转位 return chromosome3. 完整算法流程与参数调优现在我们将所有组件组合起来实现完整的遗传算法def genetic_algorithm(generations100): population initialize_population() best_solution None best_fitness 0 for gen in range(generations): # 评估适应度 fitnesses [calculate_fitness(chromo) for chromo in population] # 记录最佳解 current_best max(fitnesses) if current_best best_fitness: best_fitness current_best best_index fitnesses.index(current_best) best_solution population[best_index] # 选择 selected tournament_selection(population, fitnesses) # 交叉与变异 new_population [] for i in range(0, len(selected), 2): parent1, parent2 selected[i], selected[i1] child1, child2 crossover(parent1, parent2) child1 mutate(child1) child2 mutate(child2) new_population.extend([child1, child2]) population new_population # 打印进度 print(fGeneration {gen1}: Best Fitness {best_fitness}) return best_solution, best_fitness3.1 关键参数影响分析遗传算法的性能很大程度上取决于参数设置。以下是主要参数的影响及调优建议参数典型范围影响调优建议种群大小50-200越大多样性越好但计算成本增加从50开始逐步增加直到性能不再提升交叉率0.7-0.9控制新解生成速度高交叉率适合简单问题复杂问题可适当降低变异率0.01-0.1维持种群多样性太小易早熟太大会破坏好解锦标赛大小2-5选择压力控制越大选择压力越大收敛越快但多样性降低3.2 运行算法与结果分析让我们运行算法并分析结果best_solution, best_value genetic_algorithm(generations50) print(\nBest Solution:) print(Selected Items:, [items[i][name] for i in range(len(best_solution)) if best_solution[i] 1]) print(Total Value:, best_value) print(Total Weight:, sum(items[i][weight] for i in range(len(best_solution)) if best_solution[i] 1))典型输出可能如下Generation 1: Best Fitness 45 Generation 2: Best Fitness 45 ... Generation 50: Best Fitness 70 Best Solution: Selected Items: [A, C, D, E] Total Value: 70 Total Weight: 13这个解选择了物品A、C、D、E总价值70总重量13kg确实是最优解之一。4. 进阶优化技巧4.1 适应度缩放技术当种群中出现超级个体时可以采用适应度缩放来平衡选择压力def scale_fitness(fitnesses): max_fit max(fitnesses) min_fit min(fitnesses) if max_fit min_fit: return [1.0] * len(fitnesses) scaled [(f - min_fit) / (max_fit - min_fit) for f in fitnesses] return scaled4.2 多种群并行进化引入多种群可以更好地保持多样性防止早熟收敛def multi_population_ga(num_populations3, migration_interval5): populations [initialize_population() for _ in range(num_populations)] best_overall None best_fitness 0 for gen in range(50): # 各独立种群进化 for i in range(num_populations): # 常规GA步骤... pass # 定期迁移 if gen % migration_interval 0: migrate(populations) return best_overall4.3 自适应参数调整让算法参数根据进化过程动态调整def adaptive_mutation(population, base_rate0.05, threshold0.1): diversity calculate_diversity(population) if diversity threshold: return base_rate * 2 # 增加变异率 return base_rate def calculate_diversity(population): # 计算种群多样性 unique len(set(tuple(chromo) for chromo in population)) return unique / len(population)5. 实际应用中的注意事项在工业级应用中遗传算法还需要考虑以下实际问题编码方式选择除了二进制编码对于连续问题可以使用实数编码对于排序问题可以使用排列编码。约束处理除了惩罚函数还可以使用修复策略或特殊算子确保解的有效性。并行化遗传算法天然适合并行计算可以利用多核CPU或GPU加速。早熟收敛检测当种群多样性过低时可以触发重启机制或增加变异率。混合算法结合局部搜索(如爬山法)形成memetic算法提升局部优化能力。# 混合遗传算法示例 def hybrid_ga(): # 常规GA步骤... # 对优秀个体进行局部搜索 for i in range(len(population)): if random.random() 0.1: # 10%概率进行局部搜索 population[i] local_search(population[i]) # 继续进化...遗传算法在背包问题上的表现证明了它在组合优化中的强大能力。通过适当调整参数和引入进阶技巧可以将其应用于更复杂的实际问题如资源调度、投资组合优化等。

更多文章