遗传算法(Genetic Algorithm,GA)
一、核心定义
遗传算法是模仿达尔文生物进化论+遗传学 的全局随机优化算法 ,由美国学者 John Holland 在20世纪70年代提出,。
简单说:模拟生物"优胜劣汰、基因交叉、变异",在海量可行解里,一步步筛选出最优/近似最优解。
二、核心生物学类比
| 生物概念 | 遗传算法对应概念 |
|---|---|
| 种群 | 一组候选解 |
| 染色体 | 单个解的编码(二进制/实数编码) |
| 基因 | 解里的单个参数 |
| 适应度 | 解的好坏评分(目标函数) |
| 选择 | 保留优质解、淘汰劣质解 |
| 交叉 | 两个优质解交换部分参数,产生新解 |
| 变异 | 随机小幅修改解,避免陷入局部最优 |
三、完整运行流程(五步循环)
- 初始化种群
随机生成一堆初始候选解,作为第一代。 - 计算适应度
给每个解打分:越接近目标,适应度越高。 - 选择(优胜劣汰)
优先保留分数高的优质个体,劣质个体大概率被淘汰。 - 交叉(基因重组)
优质个体两两结合,交换部分基因,生成下一代新解。 - 变异(随机微调)
小概率随机改动个别基因,防止算法"钻牛角尖"困在局部最优。
不断重复「评估→选择→交叉→变异」多代迭代,直到达到迭代次数/满足精度,输出最优解。
四、关键特点
优点
- 全局搜索,不容易卡在局部最优;
- 不要求目标函数连续、可导,复杂非线性问题也能用;
- 并行搜索,同时处理大量候选解,适合多维、复杂优化。
缺点
- 属于启发式算法,不一定算出绝对全局最优,多为近似最优;
- 超参数(交叉概率、变异概率、种群大小)需要调参;
- 迭代量大,复杂问题计算耗时较长。
五、适用场景
用来解决传统数学方法难算的优化问题:
- 组合优化:路径规划(旅行商TSP)、排课、仓库布局;
- 函数寻优:多峰、非线性复杂函数最大值/最小值求解;
- 工程设计:结构参数优化、电路设计、PID参数整定;
- 机器学习:特征筛选、神经网络权重优化;
- 生产调度、资源分配等复杂决策问题。
六、极简例子
比如:求一个复杂函数的最小值
- 随机生成100组自变量(种群);
- 代入函数算结果,结果越小适应度越高;
- 选结果最好的50组,互相交叉组合、少量随机变异;
- 生成新100组,循环100代;
- 最后一代里数值最小的,就是近似最优解。
补充:和普通算法区别
- 传统梯度算法:单点搜索,顺着坡度走,容易困在局部最优;
- 遗传算法:种群多点并行搜索,靠进化迭代,适合复杂无规则的优化问题。
TSP问题是什么? 它与遗传算法有何关系?
一、TSP 问题是什么
1. 全称
TSP = 旅行商问题(Traveling Salesman Problem)
2. 通俗定义
一个商人要走遍N 个城市:
- 每个城市必须走且只能走一次
- 最终回到起点
- 求总路程最短的行走路线
给定一系列城市和每对城市之间的距离,求解一条经过每个城市恰好一次并最终返回起点的最短路径。
用数学语言描述:
在完全无向图(或有向图)中,寻找一条总长度最小的哈密顿回路(Hamiltonian cycle)。
3. 数学本质
典型组合优化问题 + NP难问题 。
城市数量稍微变多,暴力穷举就完全算不动:
城市数为 (n),路线排列数:
\\text{路线总数} = (n-1)! \\div 2
举个例子:
- 10个城市:(181440) 条路线
- 15个城市:(435.89) 亿条路线
城市越多,暴力枚举完全不可行,传统精确算法算力爆炸。
4. 现实等价场景
物流配送路线、无人机巡检、PCB电路板打孔、景区游览规划、仓储搬运路径等,本质都是 TSP。
二、遗传算法 与 TSP 的关系
1. 核心关系
TSP 是遗传算法最经典、最常用的标杆测试案例 ;
遗传算法是解决大规模 TSP 最主流的启发式方法之一。
简单一句话:
TSP 太难精确求解,用遗传算法快速算出近似最优最短路径。
2. 遗传算法如何对应解决 TSP
把 TSP 路线,直接映射成遗传算法的「染色体」:
| 遗传算法概念 | TSP 问题对应内容 |
|---|---|
| 个体/染色体 | 一条城市行走顺序路线,如:[1,3,5,2,4,1] |
| 基因 | 单个城市编号 |
| 种群 | 一大堆不同的行走路线 |
| 适应度 | 路线总距离的倒数(路程越短,适应度越高) |
| 选择 | 保留短路线、淘汰长路线 |
| 交叉 | 两条优质路线,交换片段,生成新路线 |
| 变异 | 随机交换两个城市顺序,跳出局部最差路线 |
3. 为什么遗传算法适合 TSP
- TSP 是非线性、不连续、无梯度的组合问题,传统微积分、梯度优化完全用不了;
- 遗传算法是全局随机搜索,不会卡在某一条局部短路线;
- 不用遍历全部排列,迭代进化快速收敛到近最优解;
- 城市数量越大,相比暴力算法优势越明显。
4. 局限性
遗传算法算出的是近似最优解,不一定是全局绝对最短,但在工程里完全够用,效率极高。
三、总结
- TSP:走遍所有城市仅一次、回路最短的路径规划难题,属于NP难问题;
- 二者关系 :
- TSP 是遗传算法的经典应用场景+教学范例;
- 遗传算法是高效求解大规模 TSP 的核心算法;
- 通过选择、交叉、变异不断优化行走顺序,快速得到最短近似路线。
下面是一份 极简、可直接运行的**Python 遗传算法求解 TSP **完整代码,注释清晰、易懂。
python
import math
import random
# 1. 城市坐标
cities = [
(2, 3),
(5, 8),
(1, 9),
(7, 2),
(4, 6),
(8, 7)
]
city_num = len(cities)
# 2. 计算两个城市距离
def distance(city1, city2):
return math.hypot(city1[0]-city2[0], city1[1]-city2[1])
# 3. 计算一条路线总长度
def calc_path_len(path):
length = 0
for i in range(city_num - 1):
length += distance(cities[path[i]], cities[path[i+1]])
# 回到起点,形成回路
length += distance(cities[path[-1]], cities[path[0]])
return length
# 4. 遗传算法核心参数
pop_size = 50 # 种群数量
gen_num = 200 # 迭代代数
cross_rate = 0.8 # 交叉概率
mutate_rate = 0.1 # 变异概率
# 初始化种群:随机生成路线
population = []
for _ in range(pop_size):
path = list(range(city_num))
random.shuffle(path)
population.append(path)
# 选择:轮盘赌 + 保留最优
def select(pop):
fit_list = [1 / calc_path_len(p) for p in pop]
total_fit = sum(fit_list)
new_pop = []
# 精英保留:直接保留当前最优
best = pop[fit_list.index(max(fit_list))]
new_pop.append(best)
# 轮盘赌选择
for _ in range(pop_size - 1):
r = random.uniform(0, total_fit)
cur = 0
for idx, f in enumerate(fit_list):
cur += f
if cur >= r:
new_pop.append(pop[idx])
break
return new_pop
# 交叉:顺序交叉(适配TSP,避免重复城市)
def cross(p1, p2):
if random.random() > cross_rate:
return p1.copy()
left = random.randint(0, city_num-2)
right = random.randint(left+1, city_num-1)
child = [None] * city_num
child[left:right+1] = p1[left:right+1]
# 填充剩余城市
idx = 0
for node in p2:
if node not in child:
while child[idx] is not None:
idx += 1
child[idx] = node
return child
# 变异:随机交换两个城市
def mutate(path):
if random.random() < mutate_rate:
i, j = random.sample(range(city_num), 2)
path[i], path[j] = path[j], path[i]
return path
# 进化一代
def evolve(pop):
new_pop = select(pop)
children = []
for i in range(0, pop_size, 2):
p1 = new_pop[i]
p2 = new_pop[i+1] if i+1 < pop_size else new_pop[i]
c1 = cross(p1, p2)
c2 = cross(p2, p1)
children.append(mutate(c1))
children.append(mutate(c2))
return children
# 主循环
if __name__ == "__main__":
best_path = None
best_len = float("inf")
for g in range(gen_num):
population = evolve(population)
# 记录每代最优
cur_best = min(population, key=calc_path_len)
cur_len = calc_path_len(cur_best)
if cur_len < best_len:
best_len = cur_len
best_path = cur_best
if (g + 1) % 50 == 0:
print(f"第{g+1}代 | 最短距离: {best_len:.2f}")
print("\n===== 最终结果 =====")
print("最优路线城市顺序:", best_path)
print("最短回路总距离:{:.2f}".format(best_len))
代码对应关系(GA ↔ TSP)
- 染色体 :城市访问顺序列表
[0,2,5,1,...] - 适应度 :
1/路线总长,路程越短适应度越高 - 选择:保留短路径路线
- 交叉:特殊顺序交叉,保证城市不重复
- 变异:交换两座城市位置,跳出局部最优
运行效果
迭代 200 代,逐步收敛到近似最优闭环路径,城市数量增加也能正常运行。