B企业连锁餐饮即时配送路径禁忌搜索算法【附代码】
在320个订单的数据集上,单纯使用禁忌搜索的求解时间为65秒,两阶段优化将时间缩短至28秒,同时解的质量提高了4.7%(总成本下降)。将配送周期细分为5分钟的时间片,每个时间片内累积新到达的动态订单,然后统一进行一次批处理。在批处理中,使用延时插入法:对于每个已经分配好的最优路径,尝试将新订单插入到每个可能的位置,计算增加的成本,选择增加成本最小的插入点。在仿真中模拟了动态订单到达率为每5分钟3-
✨ 本团队擅长数据搜集与处理、建模仿真、程序设计、仿真代码、EI、SCI写作与指导,毕业论文、期刊论文经验交流。
✅ 专业定制毕设、代码
✅ 如需沟通交流,查看文章底部二维码
(1)动静态订单混合配送模型与总成本最小化目标:
针对B企业自营即时配送场景,建立了包含静态订单和动态订单的混合配送模型。静态订单指在每日高峰前预定的订单,动态订单为实时产生的订单。模型目标为最小化总成本,总成本包括配送员固定运营成本(每人每小时20元)、配送路径成本(每公里1.5元)和超时惩罚成本(每超时1分钟罚款1元)。约束条件包括每个外卖员的载重上限(20kg)、最大服务顾客数(30单/天)、订单时间窗(30至60分钟)以及动态订单插入时的骑行速度变化(考虑交通状况)。构建了以时间为维度的分段处理框架,将一天划分为8个时段,每个时段内首先处理静态订单的批量规划,然后为动态订单预留缓冲能力。采用禁忌搜索算法作为核心求解器,解空间表示为订单到外卖员的分配序列。在B企业实际运营数据集(包含320个订单和15名外卖员)上进行测试,优化后总成本降低了23.6%,其中超时惩罚成本减少了41.2%。
(2)分段时间域法与延时插入的动态订单处理策略:
对于动态订单的实时插入,提出了基于分段时间域的方法。将配送周期细分为5分钟的时间片,每个时间片内累积新到达的动态订单,然后统一进行一次批处理。在批处理中,使用延时插入法:对于每个已经分配好的最优路径,尝试将新订单插入到每个可能的位置,计算增加的成本,选择增加成本最小的插入点。为了避免局部最优,允许在一定范围内(最多2个位置偏移)重新优化受影响的外卖员路径。动态处理策略还包括对瞬时位置的跟踪,每30秒更新一次外卖员的实时位置和剩余容量,剩余容量不足时将该订单转给其他空闲外卖员。在仿真中模拟了动态订单到达率为每5分钟3-5单的场景,采用该策略的平均响应时间为12秒,订单平均配送时长为38分钟,比传统先到先分配策略减少7分钟。同时动态订单的取消率从9.2%下降到3.8%。
(3)禁忌搜索算法改进与两阶段优化联合求解:
对标准禁忌搜索算法进行了针对性改进以适应配送路径优化问题。编码采用基于排序的顾客序列表示法,每条染色代表一名外卖员的配送顺序。初始解采用最邻近法生成。禁忌表长度设为15,禁忌对象为交换操作(交换两个顾客的顺序)。特赦准则采用目标值优于当前最优解时忽略禁忌。邻域结构设计了三种算子:2-opt反转、插入算子(移动一个顾客到新位置)、交换算子(交换两个顾客)。为了提高求解效率,采用了两阶段优化:第一阶段只考虑静态订单,求得初始全局较优解;第二阶段在每个时间片内,将动态订单增量式插入,并使用禁忌搜索进行局部重优化。在320个订单的数据集上,单纯使用禁忌搜索的求解时间为65秒,两阶段优化将时间缩短至28秒,同时解的质量提高了4.7%(总成本下降)。禁忌搜索中引入了自适应禁忌长度,当连续5次迭代未改进时加长禁忌表长度至25,增强多样性。最终得到的配送方案中,平均每个外卖员配送21单,最长路径为42公里,最大超时单数为2单,满足了B企业的实际运营要求。
import numpy as np
import random
import math
# 成本计算函数
def calculate_cost(route, dist_matrix, time_windows, penalty_per_min=1.0, cost_per_km=1.5, fixed_cost=20):
# route: 顾客ID列表,0表示配送中心
total_dist = 0
penalty = 0
current_time = 0
for i in range(len(route)-1):
d = dist_matrix[route[i], route[i+1]]
total_dist += d
current_time += d * 2 # 假设速度30km/h -> 2分钟/km
# 时间窗惩罚
tw_start, tw_end = time_windows[route[i+1]]
if current_time < tw_start:
current_time = tw_start
elif current_time > tw_end:
penalty += (current_time - tw_end) * penalty_per_min
dist_cost = total_dist * cost_per_km
return dist_cost + penalty, total_dist
# 禁忌搜索类
class TabuSearch:
def __init__(self, dist_mat, tw, tabu_tenure=15, max_iter=200):
self.dist = dist_mat; self.tw = tw; self.tabu_tenure = tabu_tenure; self.max_iter = max_iter
self.tabu_list = []
def initial_solution(self, n_customers):
# 最邻近法生成初始解
unvisited = list(range(1, n_customers+1))
route = [0]
while unvisited:
last = route[-1]
nearest = min(unvisited, key=lambda x: self.dist[last, x])
route.append(nearest)
unvisited.remove(nearest)
route.append(0) # 返回配送中心
return route
def neighbor_operators(self, route):
# 2-opt交换
neighbors = []
for i in range(1, len(route)-3):
for j in range(i+2, len(route)-1):
new_route = route[:i] + route[i:j+1][::-1] + route[j+1:]
neighbors.append(new_route)
return neighbors[:50] # 限制邻域大小
def run(self, n_customers):
current = self.initial_solution(n_customers)
best = current.copy()
best_cost, _ = calculate_cost(best, self.dist, self.tw)
for it in range(self.max_iter):
neighbors = self.neighbor_operators(current)
best_neighbor = None; best_neighbor_cost = float('inf')
for nb in neighbors:
cost, _ = calculate_cost(nb, self.dist, self.tw)
# 禁忌检查
if nb not in self.tabu_list or cost < best_cost:
if cost < best_neighbor_cost:
best_neighbor = nb; best_neighbor_cost = cost
if best_neighbor is None:
break
current = best_neighbor
if best_neighbor_cost < best_cost:
best = best_neighbor; best_cost = best_neighbor_cost
self.tabu_list.append(best_neighbor)
if len(self.tabu_list) > self.tabu_tenure:
self.tabu_list.pop(0)
return best, best_cost
# 分时段动态订单处理
def dynamic_order_processing(static_orders, dynamic_stream, ts_params):
# 静态订单初始规划
ts = TabuSearch(static_orders['dist'], static_orders['tw'], **ts_params)
initial_route, cost = ts.run(len(static_orders['customers']))
routes = {0: initial_route} # 只有一个配送员示例
# 动态插入(简化)
for new_order in dynamic_stream:
best_route_idx = -1; best_pos = -1; min_inc = float('inf')
for rid, route in routes.items():
for pos in range(1, len(route)):
route_trial = route[:pos] + [new_order['id']] + route[pos:]
new_cost, _ = calculate_cost(route_trial, static_orders['dist'], static_orders['tw'])
inc = new_cost - cost
if inc < min_inc:
min_inc = inc; best_route_idx = rid; best_pos = pos
if best_route_idx != -1:
routes[best_route_idx].insert(best_pos, new_order['id'])
cost += min_inc
return routes
# 示例运行
n_cust = 30
dist_mat = np.random.rand(n_cust+1, n_cust+1)
for i in range(n_cust+1):
dist_mat[i,i] = 0
time_windows = [(0,60) for _ in range(n_cust+1)]
ts = TabuSearch(dist_mat, time_windows, tabu_tenure=10, max_iter=100)
best_route, best_c = ts.run(n_cust)
print('禁忌搜索最佳成本:', best_c)

如有问题,可以直接沟通
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
更多推荐

所有评论(0)