针对速冻食品冷链配送路径优化问题,提出一个完整的带时间窗和多重成本因素的数学模型及其粒子群算法(PSO)求解的 MATLAB 实现。代码采用随机键编码 + 解码过程处理离散的车辆路径问题,并充分考虑了冷链物流特有的运输成本、制冷成本、货损成本和时间窗惩罚。
1. 问题描述与数学模型
1.1 场景设定
- 1 个配送中心(编号 0),N 个客户点(编号 1...N)
- 多辆同质冷藏车,容量 Q,匀速行驶
- 每个客户有需求量、期望服务时间窗 [ETi,LTi][ET_i, LT_i][ETi,LTi]、服务时间
- 目标:安排车辆路径,使得总成本最小
1.2 成本构成
- 运输成本:与行驶距离成正比
- 制冷成本:运输途中恒温制冷 + 开门卸货时的额外制冷
- 货损成本:运输时间及开门时间造成的货物品质下降
- 时间窗惩罚 :早于 ETiET_iETi等待惩罚,晚于LTiLT_iLTi延时惩罚(可设硬/软时间窗,此处用软时间窗)
1.3 符号说明(见代码注释)
2. 粒子群算法设计
2.1 编码与解码
- 粒子位置向量维度:NNN维连续变量,范围 [0,1][0,1][0,1]
- 解码方法:对位置分量排序 → 得到客户的访问优先顺序;再根据容量和时间窗约束切分成多条路径。
2.2 适应度函数
- 按照解码出的路径计算上述四项成本之和。
2.3 粒子速度和位置更新
- 标准 PSO 公式,引入惯性权重线性递减,加速系数 c1,c2c_1, c_2c1,c2。
3. MATLAB 代码
下面是实现上述方案的完整代码,直接复制到 MATLAB 中即可运行。
matlab
%% 粒子群算法求解速冻食品冷链配送路径优化问题
% 带时间窗、多成本因素的车辆路径问题(VRPTW), 使用随机键PSO
clear; clc; close all;
%% 1. 问题参数设置
rng(42) % 随机数种子,保证可复现
N_customer = 15; % 客户数量
N_vehicle = 5; % 可用车辆数
Q = 80; % 车辆容量
speed = 60; % 行驶速度 (km/h)
% 配送中心坐标 (0号)
depot = [50, 50];
% 随机生成客户坐标 (0~100)
customer_pos = rand(N_customer, 2) * 100;
% 合并所有节点坐标: 1行为配送中心, 2~N+1行为客户
node = [depot; customer_pos];
% 客户需求量 (随机10~30)
demand = randi([10, 30], N_customer, 1);
% 服务时间 (h) 随机0.1~0.3
service_time = 0.1 + 0.2*rand(N_customer, 1);
% 时间窗: 在总时长12h内随机生成,窗口宽度2h
TW_width = 2;
ET = 1 + 9*rand(N_customer,1); % 最早到达时间
LT = ET + TW_width; % 最晚到达时间
% 成本系数
c_trans = 10; % 单位距离运输成本
c_ref = 5; % 运输途中单位时间制冷成本
c_open = 8; % 开门卸货单位时间额外制冷成本
c_loss = 2; % 单位时间货损成本(运输+开门)
c_early = 15; % 早到等待惩罚(每小时)
c_late = 20; % 晚到惩罚(每小时)
% 距离矩阵 (欧氏距离)
dist_matrix = squareform(pdist(node)); % (N+1)x(N+1)
%% 2. PSO参数
swarm_size = 100; % 粒子数
max_iter = 200; % 最大迭代次数
dim = N_customer; % 搜索空间维度 = 客户数
w_max = 0.9; % 惯性权重最大值
w_min = 0.4; % 惯性权重最小值
c1 = 1.5; % 认知学习因子
c2 = 1.5; % 社会学习因子
% 初始化位置 (0~1随机)
pos = rand(swarm_size, dim);
vel = -0.1 + 0.2*rand(swarm_size, dim); % 速度在[-0.1,0.1]
% 个体最优
p_best_pos = pos;
p_best_val = inf(swarm_size, 1);
% 全局最优
g_best_pos = zeros(1, dim);
g_best_val = inf;
% 计算初始适应度
for i = 1:swarm_size
p_best_val(i) = fitness(pos(i,:), dist_matrix, demand, ET, LT, ...
service_time, Q, speed, N_vehicle, ...
c_trans, c_ref, c_open, c_loss, c_early, c_late);
if p_best_val(i) < g_best_val
g_best_val = p_best_val(i);
g_best_pos = pos(i,:);
end
end
best_fit_history = zeros(max_iter, 1); % 记录迭代最优值
%% 3. PSO迭代主循环
for iter = 1:max_iter
w = w_max - (w_max - w_min) * iter / max_iter; % 惯性权重线性递减
for i = 1:swarm_size
% 更新速度
r1 = rand(1,dim); r2 = rand(1,dim);
vel(i,:) = w * vel(i,:) ...
+ c1 * r1 .* (p_best_pos(i,:) - pos(i,:)) ...
+ c2 * r2 .* (g_best_pos - pos(i,:));
% 速度边界处理
vel(i,:) = max(vel(i,:), -0.15);
vel(i,:) = min(vel(i,:), 0.15);
% 更新位置
pos(i,:) = pos(i,:) + vel(i,:);
% 位置边界处理 [0,1]
pos(i,:) = max(pos(i,:), 0);
pos(i,:) = min(pos(i,:), 1);
% 计算新适应度
new_val = fitness(pos(i,:), dist_matrix, demand, ET, LT, ...
service_time, Q, speed, N_vehicle, ...
c_trans, c_ref, c_open, c_loss, c_early, c_late);
% 更新个体最优
if new_val < p_best_val(i)
p_best_val(i) = new_val;
p_best_pos(i,:) = pos(i,:);
end
% 更新全局最优
if new_val < g_best_val
g_best_val = new_val;
g_best_pos = pos(i,:);
end
end
best_fit_history(iter) = g_best_val;
if mod(iter,20)==0
fprintf('迭代 %d, 全局最优成本 = %.2f\n', iter, g_best_val);
end
end
%% 4. 结果输出与可视化
fprintf('\n====== 最终优化结果 ======\n');
fprintf('最优总成本: %.2f\n', g_best_val);
% 解码最优粒子的路径
[~, routes] = fitness(g_best_pos, dist_matrix, demand, ET, LT, ...
service_time, Q, speed, N_vehicle, ...
c_trans, c_ref, c_open, c_loss, c_early, c_late);
disp('各车辆路径:');
for v = 1:length(routes)
if ~isempty(routes{v})
fprintf('车辆 %d: 0 -> ', v);
fprintf('%d -> ', routes{v});
fprintf('0\n');
end
end
% 绘制收敛曲线
figure;
plot(best_fit_history, 'LineWidth', 1.5);
xlabel('迭代次数'); ylabel('最优总成本');
title('PSO 收敛曲线'); grid on;
% 绘制路径图
figure; hold on;
colors = lines(N_vehicle);
% 画配送中心
plot(depot(1), depot(2), 'rp', 'MarkerSize', 15, 'MarkerFaceColor', 'r');
text(depot(1)+1, depot(2)+1, '配送中心');
% 画客户点
plot(customer_pos(:,1), customer_pos(:,2), 'bo', 'MarkerSize', 6, 'MarkerFaceColor', 'b');
for k = 1:N_customer
text(customer_pos(k,1)+1, customer_pos(k,2)+1, num2str(k));
end
% 画路径
for v = 1:length(routes)
if isempty(routes{v}), continue; end
r = [0, routes{v}, 0]; % 加上配送中心
for i = 1:length(r)-1
plot([node(r(i)+1,1), node(r(i+1)+1,1)], ...
[node(r(i)+1,2), node(r(i+1)+1,2)], ...
'Color', colors(v,:), 'LineWidth', 2);
% 画方向箭头
dx = node(r(i+1)+1,1) - node(r(i)+1,1);
dy = node(r(i+1)+1,2) - node(r(i)+1,2);
quiver(node(r(i)+1,1), node(r(i)+1,2), dx*0.9, dy*0.9, 0, ...
'Color', colors(v,:), 'MaxHeadSize', 0.5);
end
end
xlabel('X 坐标'); ylabel('Y 坐标');
title('最优冷链配送路径');
axis equal; grid on; hold off;
%% =================== 适应度函数 ===================
function [cost, routes] = fitness(x, dist_matrix, demand, ET, LT, ...
service_time, Q, speed, N_vehicle, ...
c_trans, c_ref, c_open, c_loss, c_early, c_late)
% x: 粒子位置向量 (1 x N_customer)
% 返回值 cost: 总成本, routes: cell数组,每个cell存放访问序列
N = length(x);
[~, order] = sort(x); % 随机键解码:排序得访问优先顺序
routes = cell(N_vehicle, 1); % 存储每个车辆的路径(客户编号)
cur_route = [];
cur_load = 0;
v = 1;
% 按照order顺序将客户分配到各车辆(考虑容量)
for i = 1:N
cust = order(i);
if cur_load + demand(cust) <= Q
cur_route = [cur_route, cust];
cur_load = cur_load + demand(cust);
else
% 当前车辆满载,保存路径,启用下一辆车
if ~isempty(cur_route)
routes{v} = cur_route;
v = v + 1;
end
if v > N_vehicle
% 超出车辆数,施加极大惩罚(不可行解)
cost = 1e6;
return;
end
cur_route = cust;
cur_load = demand(cust);
end
end
if ~isempty(cur_route) && v <= N_vehicle
routes{v} = cur_route;
end
% 计算总成本
total_cost = 0;
for v = 1:N_vehicle
r = routes{v};
if isempty(r), continue; end
prev = 0; % 从配送中心出发
cur_time = 0; % 当前时间
for i = 1:length(r)
cust = r(i);
% 行驶到客户cust
travel_time = dist_matrix(prev+1, cust+1) / speed;
cur_time = cur_time + travel_time;
% 运输成本
total_cost = total_cost + c_trans * dist_matrix(prev+1, cust+1);
% 运输途中制冷成本
total_cost = total_cost + c_ref * travel_time;
% 运输货损成本
total_cost = total_cost + c_loss * travel_time;
% 时间窗惩罚及等待
if cur_time < ET(cust)
wait_time = ET(cust) - cur_time;
total_cost = total_cost + c_early * wait_time; % 早到等待成本
cur_time = ET(cust); % 等待到最早时间开始服务
elseif cur_time > LT(cust)
late_time = cur_time - LT(cust);
total_cost = total_cost + c_late * late_time; % 晚到惩罚
end
% 服务时间内的开门制冷与货损
st = service_time(cust);
total_cost = total_cost + c_open * st; % 开门制冷
total_cost = total_cost + c_loss * st; % 开门货损
cur_time = cur_time + st;
prev = cust;
end
% 返回配送中心
return_travel = dist_matrix(prev+1, 1) / speed;
total_cost = total_cost + c_trans * dist_matrix(prev+1, 1);
total_cost = total_cost + c_ref * return_travel;
total_cost = total_cost + c_loss * return_travel;
end
cost = total_cost;
end
4. 代码说明
-
问题设定
- 随机生成了 15 个客户点的位置、需求量、时间窗等数据,用户可根据实际数据替换。
-
冷链成本模型
c_trans:运输距离成本c_ref:运输途中制冷(与时间成正比)c_open:卸货开门额外制冷c_loss:货损(全程时间)c_early/c_late:软时间窗惩罚
-
PSO 优化
- 维度等于客户数,粒子位置通过
sort转化为访问顺序 - 使用容量约束切分路径,超出车辆总数直接罚以极大成本
- 适应度函数同时返回最优成本与路径信息,方便结果展示
- 维度等于客户数,粒子位置通过
-
结果输出
- 打印每辆车的最优路径
- 画出收敛曲线与路径示意图
