1. 卡车多工地调度问题概述
在工程物流和建筑运输领域,卡车多工地调度是一个典型的组合优化问题。这个问题可以描述为:在给定一组卡车资源和多个工地需求的情况下,如何合理安排每辆卡车的行驶路线和服务顺序,使得在满足各种约束条件的前提下,实现运输成本最小化或效率最大化。
这类问题的复杂性主要体现在三个方面:首先,工地通常有严格的时间窗限制,比如混凝土浇筑必须在特定时间段内完成;其次,卡车有载重限制,不能无限制装载货物;最后,还需要考虑路线优化、等待时间、司机工作时间等多重因素。传统的人工调度方法在面对超过10个工地、5辆卡车以上的场景时,往往难以找到最优解,甚至难以找到可行解。
2. 粒子群算法原理与优势
2.1 粒子群算法基本原理
粒子群优化算法(PSO)是一种基于群体智能的优化技术,灵感来源于鸟群觅食行为。算法中,每个"粒子"代表问题的一个潜在解,这些粒子在解空间中飞行,通过跟踪个体最优解(pbest)和群体最优解(gbest)来不断调整自己的位置和速度。
PSO的核心公式包括速度更新和位置更新两个部分:
code复制v_i(t+1) = w*v_i(t) + c1*r1*(pbest_i - x_i(t)) + c2*r2*(gbest - x_i(t))
x_i(t+1) = x_i(t) + v_i(t+1)
其中,w是惯性权重,c1和c2是学习因子,r1和r2是[0,1]范围内的随机数。
2.2 PSO在调度问题中的优势
相比其他优化算法,PSO特别适合解决卡车调度问题,主要体现在:
- 并行搜索能力:多个粒子同时探索解空间,提高了找到全局最优解的概率
- 记忆特性:粒子会记住个体最优和群体最优解,避免盲目搜索
- 参数简单:只需调整粒子数、惯性权重等少量参数
- 收敛速度快:在中等规模问题上通常比遗传算法收敛更快
- 易于实现:算法结构简单,编程实现方便
在实际工程调度中,我们通常设置粒子数为50-100,惯性权重w从0.9线性递减到0.4,学习因子c1=c2=2.0,迭代次数100-200次。
3. 问题建模与算法适配
3.1 数学模型构建
对于带时间窗的多工地卡车调度问题,我们需要建立完整的数学模型:
决策变量:
- x_ijk:二进制变量,卡车k是否从工地i前往工地j
- t_ik:卡车k到达工地i的时间
- w_ik:卡车k在工地i的等待时间
目标函数:
最小化总成本 = α×总行驶距离 + β×总等待时间 + γ×总违约惩罚
约束条件:
- 时间窗约束:ET_i ≤ t_ik ≤ LT_i (ET最早时间,LT最晚时间)
- 载重约束:Σq_i ≤ Q_k (q_i工地i的需求量,Q_k卡车k的容量)
- 任务覆盖:每个工地必须被且仅被一辆卡车服务
- 连续性约束:卡车路线必须连续不中断
3.2 PSO算法适配设计
为了将PSO应用于离散的调度问题,我们需要设计特殊的编码和解码方案:
粒子编码:
采用基于工地的编码方式,例如对于3辆卡车和8个工地,一个粒子可以表示为[1,3,2,1,2,3,1,2],表示工地1由卡车1服务,工地2由卡车3服务,依此类推。
解码过程:
- 根据编码将工地分配给各卡车
- 对每辆卡车的工地序列进行TSP求解,确定最优访问顺序
- 计算各工地到达时间、等待时间等
- 评估目标函数值
适应度函数:
设计为:fitness = 1/(总成本 + ε),其中ε是极小正数避免除零。
4. 算法实现关键步骤
4.1 初始化阶段
初始化时需要特别注意:
- 生成可行解:随机生成的粒子必须满足所有硬约束(载重、全覆盖等)
- 多样性保证:初始粒子应尽可能分散在解空间不同区域
- 参数设置:根据问题规模合理确定粒子数、迭代次数等
matlab复制% MATLAB初始化示例代码
num_particles = 50; % 粒子数量
num_sites = 15; % 工地数量
num_trucks = 5; % 卡车数量
% 初始化粒子位置
particles = zeros(num_particles, num_sites);
for i = 1:num_particles
% 确保每个工地都被分配且满足载重约束
valid = false;
while ~valid
particles(i,:) = randi(num_trucks, 1, num_sites);
valid = check_constraints(particles(i,:), demands, capacities);
end
end
4.2 迭代优化过程
迭代过程中需要处理的关键问题:
- 速度更新:在离散问题中,速度可以理解为分配变化的概率
- 位置更新:采用基于概率的离散位置更新方法
- 约束处理:对不满足约束的解进行修复或惩罚
- 早熟收敛:采用动态惯性权重、变异算子等方法避免
matlab复制% PSO迭代核心代码
for iter = 1:max_iter
% 更新惯性权重
w = w_max - (w_max-w_min)*iter/max_iter;
for i = 1:num_particles
% 速度更新
v = w*v + c1*rand*(pbest_pos(i,:)-particles(i,:)) ...
+ c2*rand*(gbest_pos-particles(i,:));
% 位置更新(采用概率转移)
prob = 1./(1+exp(-v)); % sigmoid转换
new_pos = particles(i,:);
for j = 1:num_sites
if rand < prob(j)
new_pos(j) = randi(num_trucks);
end
end
% 修复不可行解
new_pos = repair_solution(new_pos, demands, capacities);
% 评估适应度
new_fitness = evaluate_fitness(new_pos, ...);
% 更新pbest和gbest
if new_fitness > pbest_fit(i)
pbest_pos(i,:) = new_pos;
pbest_fit(i) = new_fitness;
end
if new_fitness > gbest_fit
gbest_pos = new_pos;
gbest_fit = new_fitness;
end
end
end
4.3 解的质量评估
评估调度方案质量需要考虑多个指标:
- 总行驶距离(直接影响油耗和车辆损耗)
- 总等待时间(影响司机工作时间和效率)
- 违约次数(影响客户满意度和可能的经济处罚)
- 卡车利用率(反映资源使用效率)
这些指标通常需要根据具体业务场景进行加权综合,形成统一的目标函数。
5. 实际应用中的关键问题与解决方案
5.1 时间窗处理技巧
在实际工程中,时间窗处理有几个实用技巧:
- 硬时间窗与软时间窗:关键任务设为硬时间窗(必须满足),非关键任务可设为软时间窗(允许适度违反但需惩罚)
- 时间窗缓冲:在计划时预留5-10%的时间缓冲,应对突发延误
- 动态调整:根据实时交通信息动态调整到达时间预测
matlab复制% 时间窗惩罚计算示例
function penalty = time_window_penalty(arrival_time, ET, LT)
if arrival_time < ET
penalty = 0.5 * (ET - arrival_time); % 早到惩罚系数0.5
elseif arrival_time > LT
penalty = 2.0 * (arrival_time - LT); % 迟到惩罚系数2.0
else
penalty = 0;
end
end
5.2 多目标权衡策略
多目标优化常用的处理方法:
- 加权求和法:将各目标按重要性赋予权重,合并为单一目标
- 分层优化法:先优化最重要目标,再在约束下优化次要目标
- Pareto前沿法:寻找非支配解集,供决策者选择
在卡车调度中,典型权重设置可能是:
- 违约惩罚权重:1.0(最高优先级)
- 行驶距离权重:0.3
- 等待时间权重:0.1
5.3 大规模问题优化
当工地数量超过50个时,需要考虑以下优化措施:
- 分区调度:先按地理区域划分,再分别优化
- 精英保留:每代保留部分优质解不参与变异
- 并行计算:利用MATLAB并行计算工具箱加速
- 启发式初始化:用节约算法等生成优质初始解
6. MATLAB实现细节与代码解析
6.1 主算法框架
完整的MATLAB实现通常包含以下模块:
- 数据输入模块:读取工地坐标、时间窗、需求量等
- 参数设置模块:算法参数和业务参数配置
- PSO核心模块:实现粒子群优化过程
- 评估模块:计算目标函数和约束处理
- 结果输出模块:可视化及方案导出
matlab复制% 主程序框架示例
function [best_solution, best_fitness] = truck_scheduling_PSO()
% 1. 数据准备
[sites, trucks, params] = load_input_data('input.xlsx');
% 2. 参数初始化
[particles, velocities] = initialize_particles(params);
% 3. PSO迭代
for iter = 1:params.max_iter
% 评估当前种群
fitness = evaluate_population(particles, sites, trucks);
% 更新pbest和gbest
[pbest, gbest] = update_bests(particles, fitness, pbest, gbest);
% 更新粒子位置和速度
[particles, velocities] = update_particles(particles, velocities, pbest, gbest, params);
% 显示迭代信息
if mod(iter,10)==0
fprintf('Iter %d, Best Fitness: %.2f\n', iter, gbest.fitness);
end
end
% 4. 结果输出
best_solution = decode_solution(gbest.position, sites, trucks);
visualize_schedule(best_solution);
end
6.2 约束处理实现
约束处理是算法实现的关键难点,主要方法包括:
- 修复法:将不可行解调整为可行解
- 惩罚函数法:在目标函数中加入约束违反惩罚项
- 解码策略法:设计特殊的解码方式确保生成可行解
matlab复制% 修复不可行解的示例代码
function repaired = repair_solution(solution, demands, capacities)
num_trucks = max(solution);
truck_loads = zeros(1, num_trucks);
site_counts = zeros(1, length(solution));
% 计算当前各卡车载重
for i = 1:length(solution)
truck = solution(i);
truck_loads(truck) = truck_loads(truck) + demands(i);
site_counts(i) = site_counts(i) + 1;
end
% 修复超载卡车
for t = 1:num_trucks
while truck_loads(t) > capacities(t)
% 找出该卡车服务的最小需求工地
sites = find(solution == t);
[min_demand, idx] = min(demands(sites));
site_to_move = sites(idx);
% 找到有剩余容量的卡车
for t2 = 1:num_trucks
if t2 ~= t && truck_loads(t2) + demands(site_to_move) <= capacities(t2)
solution(site_to_move) = t2;
truck_loads(t) = truck_loads(t) - demands(site_to_move);
truck_loads(t2) = truck_loads(t2) + demands(site_to_move);
break;
end
end
end
end
repaired = solution;
end
6.3 性能优化技巧
提高MATLAB代码运行效率的关键点:
- 向量化运算:避免使用循环,改用矩阵运算
- 预分配内存:为大型数组预先分配内存空间
- 并行计算:使用parfor并行评估粒子适应度
- Mex文件:对关键函数用C/C++实现加速
matlab复制% 向量化适应度评估示例
function fitness = evaluate_population(particles, sites, trucks)
num_particles = size(particles,1);
fitness = zeros(num_particles,1);
% 并行计算各粒子适应度
parfor i = 1:num_particles
solution = decode_solution(particles(i,:), sites, trucks);
fitness(i) = calculate_fitness(solution, sites, trucks);
end
end
7. 工程实践中的经验与技巧
7.1 参数调优经验
经过多个实际项目的验证,总结出以下参数设置经验:
- 粒子数量:一般取问题规模的3-5倍(工地数量的3-5倍)
- 惯性权重:从0.9线性递减到0.4效果较好
- 学习因子:c1=c2=1.5-2.0,保持认知和社会平衡
- 变异概率:增加约5%的变异概率有助于避免早熟
- 迭代次数:通常100-200次足够收敛,复杂问题可增至500次
7.2 常见问题排查
在实际应用中常遇到的问题及解决方法:
- 收敛过快:增加粒子多样性,调整惯性权重,加入变异算子
- 无法找到可行解:放松初始解生成条件,或先找到任意可行解再优化
- 目标函数波动大:检查约束处理是否合理,适当调整惩罚系数
- 运行速度慢:优化评估函数,采用并行计算,减少不必要的计算
7.3 实际案例调整
在某建材配送项目中,我们遇到了特殊需求:
- 优先级工地:医院建设工地必须优先服务
- 动态需求:部分工地会在当天新增临时需求
- 车辆差异:不同卡车的油耗特性不同
解决方案:
- 在目标函数中为优先级工地设置更高的违约惩罚
- 预留10%的运力应对临时需求
- 在距离计算中考虑车辆油耗系数
8. 算法扩展与改进方向
8.1 混合智能算法
纯PSO算法仍有改进空间,可以考虑以下混合策略:
- PSO-GA混合:引入遗传算法的交叉变异操作
- PSO-局部搜索:在PSO迭代中加入变邻域搜索等局部优化
- PSO-模拟退火:用模拟退火思想控制接受劣解的概率
8.2 动态调度优化
实际场景往往是动态的,需要考虑:
- 实时交通信息:结合GPS数据动态调整路线
- 车辆故障处理:设计应急调度机制
- 需求变更:建立快速重优化流程
8.3 多车型协同调度
更复杂的场景可能涉及:
- 不同载重车型:合理安排车型与工地匹配
- 特种车辆:如混凝土泵车需要特殊调度
- 回程利用:考虑去程和回程的货物搭配
matlab复制% 多车型调度评估示例
function cost = evaluate_multi_type(solution, sites, trucks)
total_cost = 0;
for t = 1:length(trucks)
sites_served = find(solution.assigned == t);
if ~isempty(sites_served)
% 计算路线距离
route = [trucks(t).depot, sites_served, trucks(t).depot];
distance = calculate_route_distance(route, sites);
% 计算车型特定成本
truck_cost = distance * trucks(t).cost_per_km;
% 添加固定成本
truck_cost = truck_cost + trucks(t).fixed_cost;
total_cost = total_cost + truck_cost;
end
end
cost = total_cost;
end
9. 与其他算法的对比分析
9.1 与遗传算法(GA)对比
PSO和GA都是群体智能算法,但在调度问题中表现不同:
- 收敛速度:PSO通常收敛更快,适合快速求解
- 参数调节:PSO参数更少,更易调节
- 内存特性:PSO有gbest引导搜索方向,GA更依赖种群多样性
- 局部最优:GA通过交叉变异更易跳出局部最优
9.2 与模拟退火(SA)对比
SA是单点搜索算法,与PSO的主要区别:
- 搜索策略:SA通过温度控制接受劣解,PSO通过群体协作
- 并行性:PSO天然并行,SA需要额外设计实现并行
- 适用规模:SA更适合小规模问题,PSO可处理更大规模
- 实现难度:SA实现更简单,PSO需要设计编码方案
9.3 与精确算法对比
对于小规模问题,可以用精确算法如:
- 分支定界法:能得到精确最优解,但复杂度高
- 动态规划:适合特殊结构的调度问题
- 整数规划:商业求解器如CPLEX可求解
但当工地数超过20个时,精确算法通常难以在合理时间内求解。
10. 实际应用案例与效果评估
10.1 某建筑集团调度优化案例
项目背景:
- 工地数量:23个
- 卡车数量:8辆(载重5-20吨不等)
- 时间窗:2-4小时不等
- 优化目标:降低运输成本,减少违约
实施效果:
- 运输总里程减少18%
- 时间窗违约减少95%
- 计算时间:约3分钟(原人工调度需2小时)
- 年节省成本约150万元
10.2 某市政工程调度案例
特殊需求:
- 部分工地有严格的时间窗(如学校区域只能在非上课时间进出)
- 需要考虑交通限行时段
- 部分卡车有特殊通行证
解决方案:
- 在适应度函数中为特殊工地设置更高惩罚权重
- 在距离矩阵中考虑时段限行因素
- 增加卡车属性标记特殊通行权限
实施效果:
- 违章次数降为0
- 司机工作时间减少22%
- 客户投诉率下降90%
10.3 效果评估方法论
科学评估算法效果需要:
- 基准对比:与人工调度、简单启发式算法对比
- 多指标评估:不只考虑成本,还要看违约率、资源利用率等
- 统计显著性:多次运行检验结果稳定性
- 实际验证:小规模实地测试后再全面推广
11. MATLAB实现完整框架
以下是完整的MATLAB实现框架,包含所有关键组件:
matlab复制classdef TruckSchedulingPSO
properties
% 算法参数
num_particles = 50;
max_iter = 100;
w_max = 0.9;
w_min = 0.4;
c1 = 2.0;
c2 = 2.0;
% 问题数据
sites = [];
trucks = [];
% 权重参数
alpha = 0.3; % 距离权重
beta = 0.1; % 等待时间权重
gamma = 1.0; % 违约权重
end
methods
function obj = TruckSchedulingPSO(input_file)
% 构造函数,读取输入数据
[obj.sites, obj.trucks] = obj.load_data(input_file);
end
function [sites, trucks] = load_data(obj, filename)
% 从Excel文件加载工地和卡车数据
data = readtable(filename, 'Sheet', 'Sites');
sites.coords = [data.X, data.Y];
sites.demands = data.Demand;
sites.ET = data.EarliestTime;
sites.LT = data.LatestTime;
data = readtable(filename, 'Sheet', 'Trucks');
trucks.capacity = data.Capacity;
trucks.cost_per_km = data.CostPerKM;
trucks.depot = [data.DepotX, data.DepotY];
end
function [best_solution, best_fitness] = optimize(obj)
% PSO主优化流程
% 初始化粒子群
particles = obj.initialize_particles();
velocities = zeros(obj.num_particles, length(obj.sites.demands));
% 初始化pbest和gbest
pbest_pos = particles;
pbest_fit = zeros(obj.num_particles, 1);
gbest_pos = [];
gbest_fit = -inf;
% 评估初始种群
parfor i = 1:obj.num_particles
pbest_fit(i) = obj.evaluate_fitness(particles(i,:));
end
[gbest_fit, idx] = max(pbest_fit);
gbest_pos = particles(idx,:);
% PSO迭代
for iter = 1:obj.max_iter
% 更新惯性权重
w = obj.w_max - (obj.w_max-obj.w_min)*iter/obj.max_iter;
% 更新每个粒子
parfor i = 1:obj.num_particles
% 速度更新
r1 = rand(1, length(obj.sites.demands));
r2 = rand(1, length(obj.sites.demands));
velocities(i,:) = w*velocities(i,:) + ...
obj.c1*r1.*(pbest_pos(i,:)-particles(i,:)) + ...
obj.c2*r2.*(gbest_pos-particles(i,:));
% 位置更新(采用概率转移)
prob = 1./(1+exp(-velocities(i,:)));
new_pos = particles(i,:);
for j = 1:length(new_pos)
if rand < prob(j)
new_pos(j) = randi(length(obj.trucks.capacity));
end
end
% 修复不可行解
new_pos = obj.repair_solution(new_pos);
% 评估新位置
new_fitness = obj.evaluate_fitness(new_pos);
% 更新pbest
if new_fitness > pbest_fit(i)
pbest_pos(i,:) = new_pos;
pbest_fit(i) = new_fitness;
end
end
% 更新gbest
[current_best, idx] = max(pbest_fit);
if current_best > gbest_fit
gbest_pos = pbest_pos(idx,:);
gbest_fit = current_best;
end
% 显示迭代信息
if mod(iter,10)==0
fprintf('Iteration %d, Best Fitness: %.2f\n', iter, gbest_fit);
end
end
% 解码最优解
best_solution = obj.decode_solution(gbest_pos);
best_fitness = gbest_fit;
end
function particles = initialize_particles(obj)
% 初始化粒子群,确保满足载重约束
particles = zeros(obj.num_particles, length(obj.sites.demands));
for i = 1:obj.num_particles
valid = false;
while ~valid
% 随机分配工地到卡车
particles(i,:) = randi(length(obj.trucks.capacity), 1, length(obj.sites.demands));
% 检查载重约束
valid = true;
for t = 1:length(obj.trucks.capacity)
assigned = (particles(i,:) == t);
if sum(obj.sites.demands(assigned)) > obj.trucks.capacity(t)
valid = false;
break;
end
end
end
end
end
function fitness = evaluate_fitness(obj, solution)
% 评估解的适应度
total_cost = 0;
% 计算各卡车的路线成本
for t = 1:length(obj.trucks.capacity)
sites_served = find(solution == t);
if ~isempty(sites_served)
% 对工地序列进行TSP排序
ordered_route = obj.solve_tsp(sites_served, t);
% 计算路线距离
route = [obj.trucks.depot(t,:); obj.sites.coords(ordered_route,:); obj.trucks.depot(t,:)];
distances = sqrt(sum(diff(route).^2, 2));
total_distance = sum(distances);
% 计算时间窗违约
[total_penalty, total_wait] = obj.calculate_time_info(ordered_route, t);
% 累加总成本
total_cost = total_cost + ...
obj.alpha * total_distance + ...
obj.beta * total_wait + ...
obj.gamma * total_penalty;
end
end
% 适应度为成本的倒数
fitness = 1 / (total_cost + 1e-6);
end
function ordered_route = solve_tsp(obj, sites, truck_id)
% 简化版TSP求解(实际中可用专业算法)
% 这里使用最近邻启发式算法
if length(sites) == 1
ordered_route = sites;
return;
end
current_pos = obj.trucks.depot(truck_id,:);
remaining_sites = sites;
ordered_route = [];
while ~isempty(remaining_sites)
% 找出最近的工地
dists = sqrt(sum((obj.sites.coords(remaining_sites,:) - current_pos).^2, 2));
[~, idx] = min(dists);
nearest_site = remaining_sites(idx);
% 添加到路线
ordered_route = [ordered_route, nearest_site];
current_pos = obj.sites.coords(nearest_site,:);
% 从剩余列表中移除
remaining_sites(idx) = [];
end
end
function [total_penalty, total_wait] = calculate_time_info(obj, route, truck_id)
% 计算时间窗违约和等待时间
current_time = 0; % 假设从时间0出发
depot = obj.trucks.depot(truck_id,:);
total_penalty = 0;
total_wait = 0;
% 从仓库出发
prev_pos = depot;
for i = 1:length(route)
site = route(i);
% 计算行驶时间(假设速度恒定)
distance = norm(obj.sites.coords(site,:) - prev_pos);
travel_time = distance / 50 * 60; % 50km/h,转换为分钟
% 到达时间
arrival_time = current_time + travel_time;
% 计算时间窗违约
if arrival_time < obj.sites.ET(site)
% 早到需要等待
wait_time = obj.sites.ET(site) - arrival_time;
total_wait = total_wait + wait_time;
arrival_time = obj.sites.ET(site);
elseif arrival_time > obj.sites.LT(site)
% 迟到产生违约
penalty = arrival_time - obj.sites.LT(site);
total_penalty = total_penalty + penalty;
end
% 服务时间(假设每个工地需要30分钟)
service_time = 30;
current_time = arrival_time + service_time;
prev_pos = obj.sites.coords(site,:);
end
% 返回仓库
distance = norm(depot - prev_pos);
travel_time = distance / 50 * 60;
current_time = current_time + travel_time;
end
function repaired = repair_solution(obj, solution)
% 修复不可行解(确保满足载重约束)
truck_loads = zeros(1, length(obj.trucks.capacity));
site_counts = zeros(1, length(solution));
% 计算当前各卡车载重
for i = 1:length(solution)
truck = solution(i);
truck_loads(truck) = truck_loads(truck) + obj.sites.demands(i);
site_counts(i) = site_counts(i) + 1;
end
% 修复超载卡车
for t = 1:length(obj.trucks.capacity)
while truck_loads(t) > obj.trucks.capacity(t)
% 找出该卡车服务的最小需求工地
sites = find(solution == t);
[min_demand, idx] = min(obj.sites.demands(sites));
site_to_move = sites(idx);
% 找到有剩余容量的卡车
for t2 = 1:length(obj.trucks.capacity)
if t2 ~= t && truck_loads(t2) + obj.sites.demands(site_to_move) <= obj.trucks.capacity(t2)
solution(site_to_move) = t2;
truck_loads(t) = truck_loads(t) - obj.sites.demands(site_to_move);
truck_loads(t2) = truck_loads(t2) + obj.sites.demands(site_to_move);
break;
end
end
end
end
repaired = solution;
end
function solution = decode_solution(obj, encoded_solution)
% 解码粒子为完整的调度方案
solution = struct();
for t = 1:length(obj.trucks.capacity)
sites_served = find(encoded_solution == t);
if ~isempty(sites_served)
% 求解TSP顺序
ordered_route = obj.solve_tsp(sites_served, t);
% 计算到达时间和等待时间
[time_info, total_distance] = obj.calculate_route_details(ordered_route, t);
% 存储卡车路线信息
solution(t).sites = ordered_route;
solution(t).arrival_times = time_info.arrival_times;
solution(t).wait_times = time_info.wait_times;
solution(t).penalties = time_info.penalties;
solution(t).total_distance = total_distance;
solution(t).total_cost = obj.alpha * total_distance + ...
obj.beta * sum(time_info.wait_times) + ...
obj.gamma * sum(time_info.penalties);
else
solution(t).sites = [];
solution(t).arrival_times = [];
solution(t).wait_times = [];
solution(t).penalties = [];
solution(t).total_distance = 0;
solution(t).total_cost = 0;
end
end
end
function visualize_schedule(obj, solution)
% 可视化调度方案
figure;
hold on;
% 绘制所有工地
scatter(obj.sites.coords(:,1), obj.sites.coords(:,2), 100, 'b', 'filled');
% 绘制仓库位置
colors = lines(length(obj.trucks.capacity));
for t = 1:length(obj.trucks.capacity)
scatter(obj.trucks.depot(t,1), obj.trucks.depot(t,2), 150, colors(t,:), 'd', 'filled');
end
% 绘制各卡车路线
for t = 1:length(solution)
if ~isempty(solution(t).sites)
route = [obj.trucks.depot(t,:);
obj.sites.coords(solution(t).sites,:);
obj.trucks.depot(t,:)];
plot(route(:,1), route(:,2), 'Color', colors(t,:), 'LineWidth', 2);
% 标注工地顺序
for i = 1:length(solution(t).sites)
text(obj.sites.coords(solution(t).sites(i),1), ...
obj.sites.coords(solution(t).sites(i),2), ...
sprintf('%d(%d)', i, t), ...
'HorizontalAlignment', 'center');
end
end
end
title('卡车调度方案可视化');
xlabel('X坐标');
ylabel('Y坐标');
grid on;
hold off;
end
end
end
12. 总结与展望
粒子群算法在卡车多工地调度问题中展现出了良好的性能,特别是在处理中等规模问题(20-50个工地)时,能够在合理时间内找到优质解。通过合理的编码设计、约束处理和参数调优,PSO算法可以有效地解决带时间窗的多目标调度问题。
在实际应用中,我们还需要考虑更多现实因素,如:
- 动态环境:实时交通状况、工地需求变更等
- 多车型协同:不同载重、不同特性的卡车配合使用
- 司机偏好:考虑司机的工作习惯和休息时间
- 天气影响:恶劣天气下的调度调整
未来可以探索的方向包括:
- 结合机器学习预测工地需求和交通状况
- 开发混合智能算法进一步提升求解质量
- 设计更友好的交互界面,方便调度人员使用
- 开发移动端应用,实现实时调度和跟踪