2020年MathorCup数学建模C题仓内拣货优化问题解题全过程文档及程序

2020年第十届MathorCup高校数学建模挑战赛

C题仓内拣货优化问题

原题再现:

  某电商公司客户订单下达仓库后,商品开始下架出库,出库主要包含5个流程如下图所示:
在这里插入图片描述
  l 定位:仓库有多个货架,每个货架有多个货格,商品摆放在货格中,且每个货格最多摆放一种商品,商品可以摆放在多个货格。订单下达仓库后,定位操作,确定商品下架的货格和每个货格下架的商品数量。
  l 组单:单个客户订单商品数量少,对于中小件商品仓库,需要将多个客户的订单合并,构成任务单,这就是组单操作。
  l 拣货:拣货开始,拣货员在某个复核台领拣货车及任务单,领取时间不计,然后根据推荐顺序依次访问任务单中商品所在货格,并下架商品,将商品放在拣货车上。下架完毕,拣货员将拣货车送往某个复核台,到达复核台后拣货员无需等待,继续领取拣货车和任务单,开始下一个任务单拣货流程。备注:(1) 拣货员开始和结束复核台可以不一致。(2) 一个拣货员负责对多个任务单时,每次只能拣一个任务单的商品。同一任务单,货格访问顺序不同,行走距离也有差异。(3) 拣货员的行走速度为 1.5m/s,商品下架过程,对任意一个货格,若下架商品数量小于 3 件,每件完成下架花费 5 秒,否则每件花费 4 秒。多人同时在一个货格拣货,不考虑等待的时间。
  l 复核和打包:拣货时,拣货员可能多拣或者漏拣商品。拣货车放到复核台先对任务中商品复核,然后将商品按照订单打包。备注:(1) 只有复核台正常工作时,才可以进行复核打包操作,每个订单复核和打包花费30 秒。(2) 只有拣货员将任务单中商品通过拣货车送到复核台后,复核台才能对该任务单中商品进行复核和打包。(3) 若一个复核台完成该复核台所有任务单的复核和打包,没有新任务前,该复核台将处于空闲状态。从0 时刻到 TOTAL_TIME 时刻,若一个复核台总空闲时间为IDLE_TIME,则该复核台利用率=1-IDLE_TIME/TOTAL_TIME。多人同时到达一个复核台时,需要考虑等待的时间。
  现有一个仓库,仓库数据见附件 1“仓库数据.xlsx”,包括 4 个表格,前 3 个表格为仓库信息,包括货架、货格、复核台的位置及大小,货格和货架的关系。第 4 个表格为任务单信息,一个任务单包含多个订单,一个订单商品包含多个货格,一个货格需要拣多件商品。仓库示意图见图 1,注意横纵坐标比例不是 1:1。
在这里插入图片描述
  根据仓库数据附件 1 和附件 2,仓库有 13 个复核台,4 排货架,其中每排 25 组货架,每组 2 个货架,共 50 个货架,每个货架包含 15 个货格。水平方向每组货架之间的距离为 1500 毫米,竖直方向相邻两排货架纵向距离为 2000 毫米,货格长宽都是 800 毫米,复核台长宽都是 1000 毫米。备注:货架和复核台为障碍物,不可通行,其余位置均可通行。不用考虑拣货车尺寸,货架和复核台高度。
在这里插入图片描述
说明:
  1. 当绕障碍物折线行走时横向和竖向偏移都取 d=750mm;
  2. 复核台之间距离简化为两复核台坐标差的绝对值之和,如复核台 A坐标 ,复核台 B 坐标 ,则两复核台距离为 ;
  3. 货格与复核台距离简化为货格中点到复核台最近一条边中点的距离,如 L1 和 L7)
  根据上述已知条件和要求,请完成以下问题:
  问题 1:图 2 给出拣货员在仓内路线示例(L1-L7)。当拣货员在仓库中拣货时,需要在货格之间、货格与复核台之间、复核台与复核台之间行走。由于这些行走通常要绕过障碍物,不能直接采用坐标计算欧几里得距离。请你按照图中距离标示,设计一种计算 3000 个货格和 13 个复核台总共 3013 个元素之间距离的方法。(附件中货架坐标可理解为第一个货格左下角坐标,如 S001 的(x,y)表示货格 S00101 的坐标。其他相类似。复核台坐标也理解为左下角坐标。)
  问题 2:假设所有复核台正常工作,任务单 T0001 等待拣货,拣货员 P在复核台 FH10 领取了任务单 T0001。请给 P 规划理想的拣货路线,包括货格访问顺序、返回的复核台,计算完成出库花费的时间(拣货员拣货开始到所有任务复核打包完成花费的时间)。
  问题 3:假设 2 个复核台 (FH03,FH11)正常工作,5 个任务单(T0002-T0006)等待拣货,继续由拣货员 P 负责拣货,P 初始位置为 FH03。通过建模和优化,请给 P 指定任务领取顺序,规划理想的拣货路线,使得这些任务尽快出库。请计算完成出库需要花费的时间和每个复核台利用率。
  问题 4:假设 4 个复核台(FH01,FH03,FH10,FH12)正常工作,49个任务单(T0001-T0049)等待拣货,9 个拣货员(P1-P9)负责拣货,请给每个拣货员分配任务单、起始拣货复核台,并分别规划理想的拣货路线,使得 49 个任务单尽快完成出库,并计算完成出库需要花费的时间和每个复核台利用率。
  问题 5:在问题 4 中,有 4 个复核台(FH01,FH03,FH10,FH12)正常工作,请评估增加一个正常工作的复核台对出库时间的影响。
  问题 6:商品在货架中的摆放位置,会影响拣货效率。若将畅销品放置在离复核台较近的位置,拣货员行走距离相应减少,但畅销品所在货架可能拥挤,反而降低拣货效率。对于仓内商品摆放问题,你有什么建议?
  注:在问题 3,4,5 中,当一个人有多个任务时,只能一个一个任务完成,不能在完成一个任务过程中拣另一个任务的货。
附件 4 计算结果文件要求说明:
  为验证计算结果,本赛题需要提交数据文件
  文件名为:C 队号计算结果.xlsx。
  问题 1 数据填入 Ques1 中,给出 3013 个元素的最短距离矩阵 3013﹡3013。 序号顺序为 S00101,S00102,…,S00115,S00201,…,S20001,S20002,…,S20015。 复核台 FH01,FH02,FH03,…,FH13。 也即 S00101 标号为 1,S00102 标号为 2,…,S20015 标号为 3000,复核台FH011标号为3001,复核台FH02标号为3002,…,FH13标号为3013。将得到的最短路矩阵填入表单 Ques1。该最短路矩阵共占 3013 行和3013 列。行从 1 行开始,列从 A 列开始。
  问题 2 数据填入 Ques2。第 2 列原始名称中 3—25 行为任务 1 中的 23 个商品货格号;第 3 列为复核台或商品货格对应的标号,范围为 1—3013。第 4 列为对应商品货格的件数,在附件仓库数据任务单中商品件数列中直接摘抄即可。复核台商品件数标 0 即可。
  问题 3 数据填入 Ques3与问题 2 表单意义相同。只是增加了一列任务单。注意当完成一个任务后,回到一个复核台,下一次即从该复核台领取任务单出发。
  问题 4 数据填入 Ques4与问题 3 表单意义相同。只是增加了一列人(P1-P9)

模型的建立与求解:

模型准备-构建元素信息矩阵

  通过观察数据文件中的序号顺序可知,S00102 表示第一个货架中第二个货格所处的位置、FH01 表示第一个复合台标号;这样的表示方式简洁明了,但其编号的不连续性会给结果的表示与输出造成一定困难。
  因此,本文先提取出数据文件中所给货格名称中的行列号,并在此基础上通过一定映射关系将3000个货格按照1-3000顺序进行编号:同时考虑将13个复核台按照3001-3013的顺序编号,从而共有3013个元素参与排序。基于此,下列通过构建元素信息矩阵L30136来对每个元素进行坐标(x,y)、其所在巷道位置以及货格所处位置等信息进行存储,方便进行各元素位置进行读取与调用。同时,考虑到货架与复核台距离计算方式的差异性,下列分别阐述货格信息矩阵( L30136中1-3000行)与复核台信息矩阵( L30136中3001-3013行)构建方法,以此得到总元素信息矩阵L30136。

  在对仓库的布局进行细致分析后发现,同一组中左右两货架的计算方式不同;为了避免对该情况进行复杂的分类讨论,本文在计算货格距离之前,构建了各货格坐标的偏移矩阵3000.,将坐标值换算到该货格紧邻的巷道中心点位置,即拣货员在取货时所处位置的外偏移量,下列给出了左右两货架两种情况下坐标偏移的计算方法。
在这里插入图片描述
  计算任意两个复核台之间的距离:
在这里插入图片描述
  问题二需要对拣货员P完成任务单T0001的拣货路线进行规划,以复核台FH10为起点,终点可从13个复核台中任意选取。基于上述分析,已经得到了任务单所有货格与复核台两两之间的距离,因此需要解决的是一个终点不确定的类旅行商问题。本问将引入一个替换终点的概念,将其转化为已知起点与终点的最短路径问题。
建立目标优化模型如下:
在这里插入图片描述
  在确定每个任务单的最短路径后,通过还原替换复核台可以确定每条路径的起点和终点。考虑到整项工作的初始起点已确定为FH03复核台,只需选择起点为FH03的任务单作为第–单,通过调整各任务单最短路径的方向或者端点的选择尽可能使得任务单之间首尾相连,即在完成一- 单任务到达复核台后,可以立即将此复核台作为下一个任务单的起点。这样,通过对各任务单最短路径下起始点与终点的组合排序,可以使得拣货员P能够在选择最短路径的前提下,连续地完成所有任务单,这将最大限度地缩短所耗时间。
在这里插入图片描述

论文缩略图:
在这里插入图片描述
在这里插入图片描述

程序代码

clc;
clear;
close all;
%% load obs
obs = load('data.csv');
numofobs = length(obs(:,1));
%% set up color map for display 
cmap = [1 1 1; ...% 1 - white - 
        0 0 0; ...% 2 - black - 
        1 0 0; ...% 3 - red - 已搜索过的地方
        0 0 1; ...% 4 - blue - 下次搜索备选中心 
        0 1 0; ...% 5 - green - 起始点
        1 1 0];...% 6 - yellow -  到目标点的路径 
colormap(cmap); 
map = zeros(25); 
% 设置障碍
for j=1:numofobs
    xobs(j) = obs(j,1);
    yobs(j) = obs(j,2);
    map(xobs(j),yobs(j)) = 2;
end
map(1,25) = 5; % 起始点
map(25,1) = 6; % 目标点
image(1.5,1.5,map);
grid on;
axis image;
%% 
nrows = 25; 
ncols = 25; 
start_node = sub2ind(size(map), 1, 25); 
dest_node = sub2ind(size(map), 25, 1); 
% Initialize distance array 
distanceFromStart = Inf(nrows,ncols); 
distanceFromStart(start_node) = 0; 
% For each grid cell this array holds the index of its parent 
parent = zeros(nrows,ncols); 
t0=clock;
% Main Loop 
while true 
 % Draw current map 
 map(start_node) = 5; 
 map(dest_node) = 6; 
 image(1.5, 1.5, map); 
 grid on; 
 axis image; 
 drawnow; 
  % Find the node with the minimum distance 
 [min_dist, current] = min(distanceFromStart(:)); 
  if ((current == dest_node) || isinf(min_dist)) 
       break; 
  end; 

 map(current) = 3; 
 distanceFromStart(current) = Inf; 
 [i, j] = ind2sub(size(distanceFromStart), current);
 neighbor = [i-1,j;... 
            i+1,j;... 
            i,j+1;... 
            i,j-1] 
outRangetest = (neighbor(:,1)<1) + (neighbor(:,1)>nrows) +...
                   (neighbor(:,2)<1) + (neighbor(:,2)>ncols ) 
locate = find(outRangetest>0); 
neighbor(locate,:)=[] 
neighborIndex = sub2ind(size(map),neighbor(:,1),neighbor(:,2)) 
for i=1:length(neighborIndex) 
if (map(neighborIndex(i))~=2) && (map(neighborIndex(i))~=3 && map(neighborIndex(i))~= 5) 
    map(neighborIndex(i)) = 4; 
  if distanceFromStart(neighborIndex(i))> min_dist + 1      distanceFromStart(neighborIndex(i)) = min_dist+1; 
        parent(neighborIndex(i)) = current; 
  end 
 end 
end 
end
TimeCost=etime(clock,t0)
%%
if (isinf(distanceFromStart(dest_node))) 
    route = []; 
else 
    %提取路线坐标
   route = [dest_node]; 
      while (parent(route(1)) ~= 0) 
              route = [parent(route(1)), route]; 
       end 
  % 动态显示出路线     
        for k = 2:length(route) - 1 
          map(route(k)) = 7; 
                pause(0.1); 
                image(1.5, 1.5, map); 
              grid on; 
              axis image; 
              end 
end
axis off;  

猜你喜欢

转载自blog.csdn.net/weixin_43292788/article/details/126495934
今日推荐