1 简介
据中国互联网络信息中心发布的第 44 次《中国互联网络发展状况统计报告》指出,截至 2019 年 6 月,我国网民规模达到 8.54 亿,较 2018 年底增长 2598 万,互联网普及率达 61.2%,其中手机网民占比高达 99.1%。庞大的网民数量为 O2O(Online ToOffline)业态的发展壮大奠定了坚实的用户基础,移动设备以及互联网的普及使得用户的 O2O 行为(连接线上线下的行为)更加高效,加上人工智能、大数据和 5G 等互联网技术的发展应用,O2O 模式得以进入更加广阔的线下领域,逐步渗透人们的日常生活。正所谓民以食为天,餐饮行业用户基数大,消费频次高,易形成较大的市场规模,因此 O2O 业态中以餐饮外卖 O2O 产业发展最为迅猛。随着业务的下沉,越来越多三四线城市的商户入驻外卖平台,用户粘性逐渐养成,外卖生态体系布局初现。目前我国外卖用户数已达 4.21 亿,占到整体网民的 49.3%,2019 年中国外卖产业交易额已突破六千亿,而外卖交易额占全国餐饮总收入比例仍在持续增长,其中一个很重要的原因是新零售时代的到来,用户需求更为多元,从单纯的餐饮领域向非餐饮、全品类跨越,实物配送需求大幅增加。如今的外卖服务已经外溢到生鲜果蔬、生活超市、美妆、日用品、服饰鞋帽和母婴产品等更多生活场景,这使得外卖成为了全时段、跨品类的重要消费场景。
外卖行业发展至今,行业格局已发生巨变,外卖商家渗透率持续提升,外卖平台多元入口引流,C 端市场格局已经稳定,白领用户的主体地位牢不可破,餐饮场景日益丰富,非正餐外卖需求(下午茶、夜宵等)增长显著。相应的,外卖智能调度系统技术不断优化,行业配送效率整体提升,外卖配送网络的服务承载持续扩大,即时配送网络已经成为基础设施,且不仅服务于餐饮外卖领域,进而为本地生活市场服务,加速推动了各项业务的全面协同。随着外卖行业的持续发展以及门槛低、回报率高的特点,外卖骑手快速扩增,外卖骑手日活跃用户数量高达 57 万,在满足人们便利性的同时,也为民众的日常出行带来了新的挑战,目前出台的相关法律制度不能对其进行很好的约束,监管难度大,民众对于外卖小哥的认可度不高,而如今外卖渗透率仍不足 15%,未来还有持续的成长空间,提升全民认可度对外卖 O2O 产业的继续发展具有重要意义。因此,外卖 O2O 模式的线下配送服务仍是当前研究的重点,如何设计合理的配送路径方案,在满足消费者需求、实现企业获得较高盈利的基础上,缓解交通状况、提高全民的认可度成为了一个亟待解决的问题
基于大连市某外卖配送站点的运营实例,针对午餐高峰时段涌入的大量订单,对骑手的配送路径进行优化.以最大化运输效率为目标,综合考虑外卖配送的实际约束,有针对性地构建骑手配送路径优化的混合整数规划模型,利用遗传算法对实例进行求解,详细分析了算法参数对优化结果的影响机理,可为外卖配送行业提供决策支持.
2 部分代码
%% 找出Removed数组中任一个元素的cheapest insertion point
%输入rv Removed数组中的任一个元素
%输入rfvc 移出removed中的顾客后的final_vehicles_customer
%输入L 集配中心时间窗
%输入a 顾客时间窗
%输入b 顾客时间窗
%输入s 服务每个顾客的时间
%输入dist 距离矩阵
%输入demands 需求量
%输入cap 最大载重量
%输出civ
%将rv插入到rfvc中在满足容量和时间窗约束下的距离增量最小的那辆车
%输出cip
%将rv插入到rfvc中在满足容量和时间窗约束下的距离增量最小的那辆车中的插入点
%输出C 将rv插入到最佳插入点后的距离增量
%思路:
%第一步:先找出满足时间窗约束和容量约束的所有插入点,再计算上述插入点的距离增量
%第二步:找出上述插入点距离增量最小的那个最佳插入点,并记录距离增量
function [civ,cip,C]= cheapestIP( rv,rfvc,L,a,b,s,dist,demands,cap,chesu,bl)
NV=size(rfvc,1); %所用车辆数
outcome=[]; %存储每一个合理的插入点以及对应的距离增量 [车辆序号 插入点序号 距离增量]
for i=1:NV
route=rfvc{i}; %其中的一条路径
len=length(route); %该路径上所经过顾客数量
LB= part_length(route,dist); %插入rv之前该条路径的距离
%先将rv插入到route中的任何空隙,共(len+1)个,
for j=1:len+1;
%将rv插入到集配中心后
if j==1
temp_r=[rv route];
LA= part_length(temp_r,dist); %插入rv之后该条路径的距离
delta=LA-LB; %插入rv之后该条路径的距离增量
[bs,back]= begin_s(temp_r,a,s,dist,chesu,bl );
%因为b是100行1列,所以需要将bs转置成多行1列的矩阵
violate_TW=(bs'<=b(temp_r)); %判断每一个顾客是否满足时间窗约束,满足为1,不满足为0
vTW=find(violate_TW==0,1,'first'); %找出violate_TW数组中不满足时间窗约束的顾客
Ld=leave_load( temp_r,demands);
%如果同时满足时间窗约束和容量约束,则该插入点合理,并记录下来
if isempty(vTW)&&(back<=L)&&(Ld<=cap)
outcome=[outcome;i j delta];
end
%将rv插入到集配中心前
elseif j==len+1
temp_r=[route rv];
LA= part_length(temp_r,dist); %插入rv之后该条路径的距离
delta=LA-LB; %插入rv之后该条路径的距离增量
[bs,back]= begin_s( temp_r,a,s,dist,chesu,bl );
%因为b是100行1列,所以需要将bs转置成多行1列的矩阵
violate_TW=(bs'<=b(temp_r)); %判断每一个顾客是否满足时间窗约束,满足为1,不满足为0
vTW=find(violate_TW==0,1,'first'); %找出violate_TW数组中不满足时间窗约束的顾客
Ld=leave_load( temp_r,demands);
%如果同时满足时间窗约束和容量约束,则该插入点合理,并记录下来
if isempty(vTW)&&(back<=L)&&(Ld<=cap)
outcome=[outcome;i j delta];
end
%将rv插入到顾客之间的任意空隙
else
temp_r=[route(1:j-1) rv route(j:end)];
LA= part_length(temp_r,dist); %插入rv之后该条路径的距离
delta=LA-LB; %插入rv之后该条路径的距离增量
[bs,back]= begin_s( temp_r,a,s,dist,chesu,bl );
%因为b是100行1列,所以需要将bs转置成多行1列的矩阵
violate_TW=(bs'<=b(temp_r)); %判断每一个顾客是否满足时间窗约束,满足为1,不满足为0
vTW=find(violate_TW==0,1,'first'); %找出violate_TW数组中不满足时间窗约束的顾客
Ld=leave_load( temp_r,demands);
%如果同时满足时间窗约束和容量约束,则该插入点合理,并记录下来
if isempty(vTW)&&(back<=L)&&(Ld<=cap)
outcome=[outcome;i j delta];
end
end
end
end
%% 如果存在合理的插入点,则找出最优插入点,否在新增加一辆车运输
if ~isempty(outcome)
addC=outcome(:,3); %每个插入点的距离增量
[saC,sindex]=sort(addC); %将距离增量从小到达排序
temp=outcome(sindex,:); %将距离增量从小到达排序后的[车辆序号 插入点序号 距离增量]
civ=temp(1,1); %第一行即为最佳插入点以及对应的距离增量
cip=temp(1,2);
C=temp(1,3);
else
civ=NV+1;
cip=1;
C=part_length(rv,dist);
end
end
%% 初始化路径
%输入cusnum 顾客数量 1-100
%输入a 左时间窗 [a,b],最早允许开始服务时间
%输入demands 每个顾客的需求量
%输入cap 车辆最大载货量
%% 先选一个12345---45123
function [init_vc] = init(cusnum,a,demands,cap)
j=ceil(rand*cusnum); %从所有顾客中随机选择一个顾客
k=1; %使用车辆数目,初始设置为1
init_vc=cell(k,1);
% 按照如下序列,遍历每个顾客,并执行以下步骤
if j==1
seq=1:cusnum;
elseif j==cusnum
seq=[cusnum,1:j-1];
else
seq1=1:j-1;
seq2=j:cusnum;
seq=[seq2,seq1];
end
%% 开始遍历
route=[]; %存储每条路径上的顾客
load=0; %初始路径上在仓库的装载量为0
i=1;
while i<=cusnum
%如果没有超过容量约束,则按照左时间窗大小,将顾客添加到当前路径
%%
if (load+demands(seq(i))<=cap)&&(size(route,1)<=20) %%%%自己家的条件****************
%%
load=load+demands(seq(i)); %初始在仓库的装载量增加
%如果当前路径为空,直接将顾客添加到路径中
if isempty(route)
route=[seq(i)];
%如果当前路径只有一个顾客,再添加新顾客时,需要根据左时间窗大小进行添加
elseif length(route)==1
if a(seq(i))<=a(route(1))
route=[seq(i),route];
else
route=[route,seq(i)];
end
else
lr=length(route); %当前路径长度,则有lr-1对连续的顾客
flag=0; %标记是否存在这样1对顾客,能让seq(i)插入两者之间
%遍历这lr-1对连续的顾客的中间插入位置
for m=1:lr-1
if (a(seq(i))>=a(route(m)))&&(a(seq(i))<=a(route(m+1)))
route=[route(1:m),seq(i),route(m+1:end)];
flag=1;
break
end
end
%如果不存在这样1对顾客,能让seq(i)插入两者之间,也就是flag=0,则需要将seq(i)插到route末尾
if flag==0
route=[route,seq(i)];
end
end
%如果遍历到最后一个顾客,则更新init_vc,并跳出程序
if i==cusnum
init_vc{k,1}=route;
break
end
i=i+1;
else %一旦超过车辆载货量约束,则需要增加一辆车
%先储存上一辆车所经过的顾客
init_vc{k,1}=route;
%然后将route清空,load清零,k加1
route=[];
load=0;
k=k+1;
end
end
end
%% 根据vehicles_customer整理出final_vehicles_customer,将vehicles_customer中空的数组移除
%输入:vehicles_customer 每辆车所经过的顾客
%输出:final_vehicles_customer 删除空数组,整理后的vehicles_customer
function [ final_vehicles_customer,vehicles_used ] = deal_vehicles_customer( vehicles_customer )
vecnum=size(vehicles_customer,1); %车辆数
final_vehicles_customer={}; %整理后的vehicles_customer
count=1; %计数器
for i=1:vecnum
par_seq=vehicles_customer{i}; %每辆车所经过的顾客
%如果该辆车所经过顾客的数量不为0,则将其所经过的顾客数组添加到final_vehicles_customer中
if ~isempty(par_seq)
final_vehicles_customer{count}=par_seq;
count=count+1;
end
end
%% 为了容易看,将上述生成的1行多列的final_vehicles_customer转置了,变成多行1列的了
final_vehicles_customer=final_vehicles_customer';
vehicles_used=size(final_vehicles_customer,1); %所使用的车辆数
end
3 仿真结果
4 参考文献
[1]靳志宏, 鞠新诚, 郭加佳,等. O2O模式下外卖骑手的配送路径优化[J]. 大连海事大学学报, 2019, 45(4):10.
博主简介:擅长智能优化算法、神经网络预测、信号处理、元胞自动机、图像处理、路径规划、无人机等多种领域的Matlab仿真,相关matlab代码问题可私信交流。
部分理论引用网络文献,若有侵权联系博主删除。