使用蚁群算法求解VRPTW问题
这里写目录标题
- 蚁群优化算法
- Python实现ACO求解VRPTW问题
- Java实现ACO求解VRPTW问题
蚁群优化算法
蚁群算法(ACO)适合求解带时间窗的车辆路径优化问题(VRPTW),主要基于其仿生智能机制与问题特性的深度契合,具体体现在以下六个方面:
-
时间窗约束的自然映射
-
信息素导向与时间窗兼容
蚂蚁在路径选择时综合评估信息素(历史经验)和启发式信息(如距离/时间成本),可无缝嵌入时间窗惩罚函数。例如:- 早到等待或晚到惩罚可转化为启发式因子(如ηᵢⱼ = 1/(行驶时间+时间窗偏离惩罚))。
- 信息素累积会优先强化满足时间窗的路径。
-
动态调整能力
信息素挥发机制(ρ参数)能逐步淘汰违反约束的路径,自适应聚焦可行解区域。
-
-
多目标协同优化
-
帕累托前沿逼近
ACO通过调整α(信息素权重)、β(启发式权重)平衡多个目标:
p i j k ∝ [ τ i j ] α ⋅ [ η i j ] β ⋅ [ 时间窗满足度 ] γ p_{ij}^k \propto [τ_{ij}]^α \cdot [η_{ij}]^β \cdot [时间窗满足度]^γ pijk∝[τij]α⋅[ηij]β⋅[时间窗满足度]γ
其中γ为时间窗权重,实现距离最短与时间合规的权衡。 -
分层优化实践
如先满足硬时间窗,再优化路径长度,可通过设计信息素更新规则实现(仅对可行解释放信息素)。
-
-
复杂约束的灵活处理
-
禁忌表(Tabu List)扩展
除记录已访问节点外,可加入:- 车辆剩余容量检查
- 节点服务时间窗校验
- 动态交通约束(如高峰时段限行)
-
混合约束编码
例如将时间窗违反量转化为目标函数惩罚项:\text{总成本} = \sum 距离 + λ \cdot \max(0, 到达时间 - 最晚时间)
-
-
动态环境适应性
-
实时信息素更新
突发情况(如某点临时关闭)可通过局部信息素重置快速响应,优于传统数学规划需重新建模。 -
在线调参机制
自适应调整α/β参数:初期高探索性(β主导),后期高开发性(α主导),提升收敛效率。
-
-
算法改进增强性能
-
精英蚂蚁策略
仅允许当代最优解更新信息素,加速高质量路径积累。 -
局部搜索嵌入
在ACO生成的解上应用2-opt*或Or-opt算法,针对性优化时间窗冲突片段。 -
并行化架构
分区域部署蚁群协作求解,适用于大规模VRPTW(如500+节点)。
-
Python实现ACO求解VRPTW问题
import numpy as np
import matplotlib.pyplot as plt
import matplotlib# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'KaiTi', 'FangSong', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号class Customer:def __init__(self, id, x, y, demand, ready_time, due_time, service_time):self.id = idself.x = xself.y = yself.demand = demandself.ready_time = ready_timeself.due_time = due_timeself.service_time = service_timedef __repr__(self) -> str:return str({"customer": self.id,"demand": self.demand,"ready_time": self.ready_time,"due_time": self.due_time,"service_time": self.service_time,})def __str__(self):return self.__repr__()def generate_customers(n_customers):np.random.seed(47)customers = [Customer(0, 50, 50, 0, 0, 200, 0)]# 只生成1个客户点(总共有2个点:仓库+客户1)for i in range(1, n_customers):x = np.random.randint(10, 90)y = np.random.randint(10, 90)demand = np.random.randint(1, 3)ready_time = np.random.randint(0, 520)due_time = ready_time + np.random.randint(30, 1440)service_time = np.random.randint(5, 10)customers.append(Customer(i, x, y, demand, ready_time, due_time, service_time))for customer in customers:print(customer)return customersclass VRPTW_ACO:def __init__(self, customers, vehicle_capacity):self.customers = customersself.n = len(customers)self.vehicle_capacity = vehicle_capacityself.dist_matrix = self._calc_dist_matrix()self.pheromone = np.ones((self.n, self.n))def _calc_dist_matrix(self):dist = np.zeros((self.n, self.n))for i in range(self.n):for j in range(self.n):dx = customers[i].x - customers[j].xdy = customers[i].y - customers[j].ydist[i][j] = np.sqrt(dx**2 + dy**2)return distdef _time_feasible(self, route, new_customer):"""时间窗检查"""temp_route = route + [new_customer]current_time = 0current_load = 0prev_customer = temp_route[0]# 检查起始点载重current_load += prev_customer.demandif current_load > self.vehicle_capacity:return Falsefor i in range(1, len(temp_route)):curr_customer = temp_route[i]# 计算旅行时间travel_time = self.dist_matrix[prev_customer.id][curr_customer.id]arrival_time = current_time + travel_time# 检查到达时间是否超过最晚时间if arrival_time > curr_customer.due_time:return False# 计算服务开始时间(考虑等待)service_start = max(arrival_time, curr_customer.ready_time)# 更新当前时间为服务结束时间current_time = service_start + curr_customer.service_time# 更新载重current_load += curr_customer.demandif current_load > self.vehicle_capacity:return Falseprev_customer = curr_customerreturn Truedef run(self, n_ants, n_iterations):best_solution = Nonebest_cost = float("inf")convergence_history = [] # 记录收敛历史for iteration in range(n_iterations):solutions = []for _ in range(n_ants):unvisited = set(range(1, self.n))routes = []current_route = [self.customers[0]]# max_attempts = 10 * self.nwhile unvisited:# max_attempts -= 1feasible = []for c_id in list(unvisited):c = self.customers[c_id]if self._time_feasible(current_route, c):pheromone = self.pheromone[current_route[-1].id][c.id]heuristic = 1 / self.dist_matrix[current_route[-1].id][c.id]feasible.append((c, pheromone**alpha * heuristic**beta))if not feasible:routes.append(current_route + [self.customers[0]])current_route = [self.customers[0]]continuetotal = sum(score for _, score in feasible)probs = [score / total for _, score in feasible]next_customer = feasible[np.random.choice(len(feasible), p=probs)][0]current_route.append(next_customer)unvisited.remove(next_customer.id)if len(current_route) > 1:routes.append(current_route + [self.customers[0]])total_cost = 0for route in routes:for i in range(len(route) - 1):total_cost += self.dist_matrix[route[i].id][route[i + 1].id]solutions.append((routes, total_cost))if total_cost < best_cost:best_solution = routesbest_cost = total_cost# 记录当前迭代的最优解