从零到一:手写一个最简单的遗传算法,看完终于理解 AI 是如何"进化"的
遗传算法的本质:不是追求完美,而是追求足够好。就像进化本身,不是设计出最完美的生物,而是设计出最能适应环境的生物。

双十一前夜,杭州某电商公司的仓库里,调度主管老张盯着屏幕发了半小时呆。
公司有300多种商品,每天要处理8000多个订单,仓库里有12条传送带、8台打包机、6辆叉车。以往靠人工排班,熟手老张需要花3个小时做一张排班表。但问题是——人工排出来的方案,往往只能做到"差不多合理",没人知道它是不是最优解。
那天晚上,老张的上级给他下了最后通牒:双十一峰值是平时的8倍,如果还是靠人排,系统崩了就全崩。
老张后来跟我复盘那个晚上,他说了一句让我印象很深的话:
"我突然意识到,仓库调度的本质不是'怎么排',而是'能不能接受一个不够好的解'。"
他最终选择的方案,让双十一期间的出库效率提升了34%,而背后的算法,核心代码不超过80行。
这个算法,叫做遗传算法(Genetic Algorithm)。
它为什么叫"遗传"
要理解遗传算法,先想一个问题:大自然是怎么让生命越来越聪明的?
不是谁设计出来的,是通过「遗传+变异+自然选择」,一代一代筛选出来的。
生物的基因会随机变异——有的突变让个体更强,有的让个体更弱。那些适应环境的基因被保留下来,继续繁殖;不适应的被淘汰。这个过程不断重复,最终整个物种越来越适应环境。
遗传算法的核心思想,就是把这件事搬到计算机里:
把一个「解」想象成一个「生物」把解的质量(比如调度效率)想象成「适应度」用「交叉」(两个解组合)和「变异」(随机改动)产生新的解用「选择」(只保留好的)来决定下一代就这么简单。没有任何高深的数学,就是"模拟进化"四个字。
80行代码:手写一个最简单的遗传算法
我们用一个最经典的问题来演示:0-1背包问题。
你有一个容量为15的背包,有5件物品,每件物品有价值(value)和重量(weight): - 物品1:v=10, w=2 - 物品2:v=5, w=3 - 物品3:v=15, w=5 - 物品4:v=7, w=4 - 物品5:v=8, w=3 问:怎么选,使得价值最大,同时不超过背包容量?
用Python实现:
import randomitems = [(10, 2), (5, 3), (15, 5), (7, 4), (8, 3)]CAPACITY = 15def create_individual(): return [random.randint(0, 1) for _ in range(len(items))]def fitness(individual): total_value = sum(v * x for (v, w), x in zip(items, individual)) total_weight = sum(w * x for (v, w), x in zip(items, individual)) if total_weight > CAPACITY: return 0 # 超重,直接判0 return total_valuedef crossover(parent1, parent2): point = random.randint(1, len(parent1) - 1) child1 = parent1[:point] + parent2[point:] child2 = parent2[:point] + parent1[point:] return child1, child2def mutate(individual): idx = random.randint(0, len(individual) - 1) individual[idx] = 1 - individual[idx] return individualdef genetic_algorithm(generatinotallow=100, pop_size=20, mutation_rate=0.1): population = [create_individual() for _ in range(pop_size)] for gen in range(generations): fitness_scores = [(ind, fitness(ind)) for ind in population] fitness_scores.sort(key=lambda x: x[1], reverse=True) parents = [ind for ind, _ in fitness_scores[:pop_size // 2]] next_gen = parents[:] while len(next_gen) < pop_size: p1, p2 = random.sample(parents, 2) c1, c2 = crossover(p1, p2) if random.random() < mutation_rate: c1 = mutate(c1) if random.random() < mutation_rate: c2 = mutate(c2) next_gen.extend([c1, c2]) population = next_gen[:pop_size] best = max(population, key=fitness) print(f"第{gen+1}代,最优解价值={fitness(best)}") return max(population, key=fitness)best = genetic_algorithm(generatinotallow=50)best_value = fitness(best)print(f"n最优方案: {best}")print(f"选中物品: {[i+1 for i, x in enumerate(best) if x == 1]}")print(f"最优价值: {best_value}")
运行结果:
第1代,最优解价值=25第10代,最优解价值=33第30代,最优解价值=40第50代,最优解价值=40最优方案: [1, 0, 1, 1, 1]选中物品: [1, 3, 4, 5]最优价值: 40
验证一下:物品1(10,2) + 物品3(15,5) + 物品4(7,4) + 物品5(8,3) = 价值40,重量14,没超载。
遗传算法真正厉害的地方
看完上面的代码,你可能会说:这也太简单了,连我写的都快!
但它的威力,恰恰来自于这种"简单"。
传统优化算法要求目标函数"可导"——也就是说,你得能对解求导数,才能知道往哪个方向调整。但现实中大量问题根本不可导:工厂排班、物流配送、投资组合,这些问题的目标函数要么是离散的,要么是凹的,要么干脆就是一个黑盒子。
遗传算法不关心这些。它只关心一件事:给一个解,能算出它的分数就行。
所以它的应用范围极广:
物流路径规划(VRP问题)神经网络结构自动设计(AutoML)电路板布局优化游戏AI的策略进化车间调度(JSP问题)三个关键参数,决定了你的算法是"进化"还是"退化"
代码虽然简单,但遗传算法有三个核心参数,调不好就会崩溃:
第一,种群规模。太小容易陷入局部最优,太大计算成本爆炸。经验值:20-100之间,小问题20足够。第二,变异率。一般设0.01-0.2。太高,算法变成随机搜索;太低,种群会快速同质化,陷入局部最优。第三,交叉率。一般设0.6-0.9。低于0.5,算法探索能力不足;高于0.9,好的解可能被破坏。这三个参数没有标准答案,靠经验和问题特点来调参。但它本身就是一种"元启发式"——不需要知道最优解在哪里,只要一代一代迭代,它自己会往好的方向走。
进化不是万能的,但它解决了一类最难的问题
回到老张的故事。
他用遗传算法做仓库排班,最后那套方案其实不是"最优解"——运筹学告诉我们,在那种规模的问题下,真正的全局最优解几乎不可能在有限时间内找到。
但它找到了一个"足够好"的解。好到什么程度?双十一当天,仓库出库量比去年同期多了47%,客诉率降到了历史最低。
这就是遗传算法的本质:不是追求完美,而是追求足够好。
就像进化本身,不是设计出最完美的生物,而是设计出最能适应环境的生物。
老张后来跟我说,他以前觉得算法这东西太高深,必须是数学博士才能搞定。
"后来我发现,真正难的不是算法本身,是你愿不愿意把一个问题'翻译'成算法能听懂的语言。"
-
08.30
夺宝奇兵:古老之圈如何全流程通关
-
08.30
新三国志曹操传沙盘1410如何打
-
08.30
巨匠眼攻略马列维奇
-
08.30
星痕共鸣新手如何进行全职业解析及推荐
-
08.30
洛克王国武生迪莫性格如何选
-
08.30
崩坏星穹铁道刹那永远成就如何完成
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏