在现代物流和配送系统中,如何高效地规划车辆路径以满足客户需求,同时最小化成本和时间,是一个备受关注的问题。传统的优化方法在面对复杂约束时往往捉襟见肘,而遗传算法(Genetic Algorithms, GA)作为一种强大的进化计算技术,为解决此类问题提供了新的思路。本文将带您深入了解如何使用 Python 实现遗传算法来优化配送路径。
背景介绍
设想您是一家配送公司的运营经理,负责规划多辆配送车辆的路径,以确保所有客户订单能够准时送达,同时最小化油费、时间成本和过载成本。这个问题涉及多个变量和约束,如客户分布、车辆载重、续航里程以及时间窗口等,传统的优化方法难以在合理时间内找到最佳解。这时,遗传算法便成为一种理想的解决方案。
什么是遗传算法?
遗传算法是一种模拟自然选择和遗传机制的优化方法。它通过种群的进化过程,不断生成新一代的解,并通过选择、交叉和变异等操作,逐步逼近问题的最优解。其核心思想包括:
- 种群初始化:随机生成一组初始解(称为个体或基因)。
- 适应度评估:评估每个个体的优劣,适应度越高,表示该解越优。
- 选择:根据适应度选择优秀个体进行繁殖。
- 交叉:通过交换父代基因生成新的子代。
- 变异:随机改变子代基因,增加种群的多样性。
- 迭代:重复上述过程,直到满足停止条件(如达到最大迭代次数或找到满意解)。
问题描述
在本案例中,我们需要解决以下配送路径优化问题:
- 配送中心:所有配送路径的起点和终点。
- 客户点:25个分布在不同位置的客户,每个客户有不同的需求量和时间窗口。
- 换电站:2个用于车辆充电的站点。
- 车辆:3辆配送车辆,每辆车有最大载重和续航里程的限制。
- 目标:在满足所有客户需求和时间窗口的前提下,最小化油费、时间成本和过载成本。
实现步骤
1. 环境准备
首先,确保您已经安装了必要的 Python 库:
pip install matplotlib tqdm
import random
import math
import matplotlib.pyplot as plt
from copy import deepcopy
from tqdm import tqdm
# 基因算法参数
geneNum = 100 # 种群数量
generationNum = 300 # 迭代次数
CENTER = 0 # 配送中心编号
HUGE = 9999999
VARY = 0.05 # 变异几率
n = 25 # 客户点数量
m = 2 # 换电站数量
k = 3 # 车辆数量
Q = 10 # 额定载重量, kg
dis = 10000 # 续航里程, km
costPerKilo = 10 # 油价
epu = 20 # 早到惩罚成本
lpu = 30 # 晚到惩罚成本
speed = 15 # 速度,km/h
# 坐标列表,包括两个换电站
X = [
56, 66, 56, 88, 88, 24, 40, 32, 16, 88, 48, 32, 80, 48, 23,
48, 16, 8, 32, 24, 72, 72, 72, 88, 104, 104, 120, 120
]
Y = [
56, 78, 27, 72, 32, 48, 48, 80, 69, 96, 96, 104, 56, 40, 16,
8, 32, 48, 64, 96, 104, 32, 16, 8, 56, 32, 80, 80
]
# 需求量列表
kg = [
0, 0.2, 0.3, 0.3, 0.3, 0.3, 0.5, 0.8, 0.4, 0.5, 0.7, 0.7,
0.6, 0.2, 0.2, 0.4, 0.2, 0.2, 0.5, 0.5, 1.2, 2.8, 1.4,
2.0, 1.9, 2.0, 1.9, 2.0
]
# 最早到达时间列表
eh = [0, 0, 1, 2, 7, 5, 3, 0, 7, 1, 4, 1, 3, 0, 2, 2, 7, 6, 7, 1, 1, 8, 6, 7, 6, 4, 8, 8]
# 最晚到达时间列表
lh = [100, 1, 2, 4, 8, 6, 5, 2, 8, 3, 5, 2, 4, 1, 4, 3, 8, 8, 9, 3, 3, 10, 10, 8, 7, 6, 9, 9]
# 服务时间列表
h = [
0, 0.2, 0.3, 0.3, 0.3, 0.3, 0.5, 0.8, 0.4, 0.5, 0.7, 0.7,
0.6, 0.2, 0.2, 0.4, 0.1, 0.1, 0.2, 0.5, 0.2, 0.7, 0.2,
0.7, 0.1, 0.5, 0.4, 0.4
]
3. 定义基因类
基因类代表了一个配送方案,包含了车辆的路径及其适应度评估。
class Gene:
def __init__(self, name='Gene', data=None):
self.name = name
self.length = n + m + 1 # 客户点 + 换电站 + 配送中心
if data is None:
self.data = self._getGene(self.length)
else:
assert (self.length + k == len(data)), f"Expected len(data)={self.length