物流设计--车辆调度模型
原题描述如下:
车辆调度模型
一、 基于配送网络和调运优先准则的物流敏捷调动优先技术
1. 支持物流敏捷调动优化的基础信息描述
(1)配送中心货物库存信息
配送中心(或调运中心,Depot)的货物库存信息由以下三元数组A表示:
A=( i, gi, qi )
其中,i表示货物编码,i=1,2,3,…, 简记为 i∈I;gi 表示货物i的规格(单位重量、体积等),并假定所有货物换算为同一规格;qi货物i的库存数量。
(2)配送点需求信息
配送点在t时刻的实时需求信息由需求矩阵C(t) 来表示
C(t)=(cij(t)) i∈I, j∈J
其中,j表示配送点编码,j=1,2,3,…,简记为j∈J;cij(t)为t时刻配送点j对货物i的需求量,t即交货期。
(3)配送网络(可行运输路径)信息
配送中心至配送点j的配送网络的信息由以下三元数组R(j)表示
R(j)=(rj,V(rj),D(rj))
其中,rj表示配送中心至配送点j的可行运输路径编码,rj=1,2,3,…,简记为rj∈Rj;
V(rj)表示路径rj上全部配送点的集合,且V(rj)={j|若配送点j位于可行运输路径rj之上,j∈J};
D(rj)表示路径rj上的配送点到配送中心的距离集,且D(rj)={d(v|rj) v∈V(rj)},
其中,d(v|rj)表示在路径rj 上配送点v到配送中心的距离,显然它不一定使配送点v到配送中心的最短距离。至于任意配送点v到配送中心的最短距离则为
D(v)=min{d(v|rv) rv∈Rv}
基于以上描述的方法,配送网络所包含的信息,因可行路径路径搜索深度和广度而异。这里提出的基于配送网络网络和调运优先准则的物流敏捷调运技术的基本前提,就是假定配送中心至其服务区域内所有陪送点的可行陪送路径已经优化。
(4)配送中心运输资源(车辆)信息
配送中心的运输车辆信息有以下三元数组E表示
E=( p, up, wp)
其中,p表示车辆编码,p=1,2,3,...,简记为p∈P;up表示车辆容量,并假定其已经换算为与gi同一量钢;wp表示车辆运行状态,wp∈{0,1},且wp=1表示车辆处于可调运状态;反之,则表示车辆处于正在运输状态。
2.物流敏捷调运优化技术的工作逻辑与思想
(1)调运优先准则
“调运优先准则”是在物流调运中根据交货期迟早、距离远近、运输量大小以及客户重要性程度等信息而对当前全部客户的物流调运优先次序进行的分类、排序。根据调运优先准则设定陪送点的当前调运优先级,进一步可以构成物流调运的递阶控制机制。调运优先准则以实现物流调运敏捷化为策略层面的首要准则,并按调运策略的层次顺序设置:
第一级调运优先准则:交货需求早的配送地要优先安排;
第二级调运优先准则:在交货期相同的配送地中,距配送中心远的优先安排;
第三级调运优先准则:针对确定的配送地,配送车辆吨位大的优先安排;
第四级调运优先准则:针对确定车辆,装载物品质量大的优先安排地方
从图可以看出,“最终配送地”是在最早交货期to有有交货需求且距离配送中心最远的配送点,而且是动态产生的。而实现物流敏捷调动的核心在于第三个工作环节:基于调运优化模型生成关于“最终配送地”的敏捷调运优化方案。
注意到针对确定的“最终配送地”j *所对应的可行运输路径集构成一个以配送中心为起点,认j*为终点的子配送网络。因此,整个逻辑整个配送网络的调运优化实际是转换成对一系列处于第一优先的子配送网络按第二优先准则的逐次调运优化。
在调运方案生成后,对基本信息进行更新。
(3)针对确定“最终配送地”调运敏捷化步骤(即③):
第一步 基于E生成当前可调用车辆集P*,P*={p︱wp=1,p∈P}。
第二步 针对由配送中心到最终配送地j*的每一条路径r(r∈Rj*)
搜索该路径上在时间t0有交货需求的配送点,并按第二优先准则对其排序,记为j(h)(其中,j(1)记为最终配送地j*)。基于路径r上配送点到配送中心的距离集D(r)生成与j(h)相对应的距离集 {d(j(h)︱r)},记为{d(h)}, 同时基于C(t)和当前库存量生成配送地j(h)的需求矩阵C(h)(t0)=[ ]。
第三步 针对各路径r,在满足j(h)在 交货的前提下,以“空载率”极小化为目标,建立调运优化模型,进行车辆配置优化和货物配载敏捷化。
第四步 在针对各路径r的调运优化模型求解后,将对应“空载率”最小的路径选出作为配送中心向“最终配送地”j*配送货物的“优选路径”,对应该路径的优化配送方案则为关于j*的敏捷调运方案,同时更新有关基础信息。
第五步 转到工作逻辑下一个工作环节,直到符合终于原则。
3.针对确定路径调运优化模型的建立及近似求解方法。
(1)针对确定路径r的调运优化模型的建立。
①决策变量的确定
设关于车辆的选择变量为 ∈{0,1},h∈ (r),L∈ 其中,t =1 表示第 号车被派往第h号主配送地 ,反之不派。
记 为第 号车派往第 号主配送地时,第k种货物的装载量。
②调运优化模型
由于调运优化的目标是“空载率”极小化,注意到路径r的空载率η(r)为
η(r)=1-( )/( ) ①
而第 j 号主配送地所需求货物总量( GGh)的计算公式为:
GG = , ②
这里, 为路径r上在时间 有交货需求的配送点集。于是,在库存和装载限制下,满足货运需求 的针对确定路径(r)的调运优化模型可由如下的非线性混合型规划问题③~⑧描述,记为NP
NP:max( )/( ) ③
⑤
⑥
⑦
⑧
其④为需求约束条件,⑤为库存约束条件,其中 为货物k的当前库存量;⑥为资源约束条件;其中 为车辆 的剩余装载量。
(2)基于确定路径调运优化模型近似求解的基本过程:
我们对调运人格化模型NP近似求解的基本思想是按确定路径r上主配送地(即在t0有交货需求的配送点)从远到近的顺序(即第二级优先准则),通过数据驱动将NP逐次分解为针对配送点j(h) 的调动优化模型NPn后,再对其递阶求解。该求解过程如下:
基于确定路径调运优化模型的递阶求解过程:
过程1:赋初值
令h=1,Fl h-1=0, P0”=
过程2:数据驱动过程
Step1:基于需求矩阵[Cih*]和当前库存量qk*(k∈I),生成针对j(h) 的满足库存限制的需求集和缺货信息并修正GGh
Step2:基于P*和上一级优化后生成的“车辆优选集”(已调用的车辆)P”h-1,生成针对j(h) 的“当前可调用车辆集”Ph*.
过程3:模型生成过程:
基NP和过程2的数据驱动生成针对确定主配送地j(h) 的调动优化模型⑨~13,记为NPh.\
NPh :max( ) / ( ) ⑨
St. = GGh ⑽
≤Ul* ⑾
thl∈{0,1} , l∈P* ⑿
xhlk≥0 , l∈P* , k∈I ⒀
过程4:NPh 求解过程
Step1:基于NPh 求得针对主配送地j(h) 的“车辆优选集”Ph及相应的最佳装载量,并计算优先级最低的车辆的剩余装载量Flh.
Step2:令h=h+1,若j(h) ∈V*(r),则转过程2;反之,则结束对(NP)的递阶求解过程。
可以看出,经过“过程2”之Step1的数据处理所生成的NPh 将自然删除关于库存约束的约束条件式⑤,再经过“过程2”之Step2的数据处理使得NPh 的规模进一步有效缩小。尽管如此,NPh 仍然是一个非线性混合型规划,关于NPh 求解过程(“过程4”之Step1)下面讨论。
4、针对确定主配送地的调运优化模型NPh 的求解:
(1)为了更有效地实现空载率极小化的目标,根据NPh 的模型的具体含义,其求解采用用基于模型驱动和数据驱动相结合的优化过程。如下:
过程1:数据驱动过程
Step1:记NPh-1求解后俦级最低车辆(不妨记该车车号为P(h-1))的“剩余装载量”为Flh-1 。然后在Flh-1 的限制下,基于需求矩阵[Cih*]并根据第四级级准则对该车进行配载,随即修正需求矩阵[Cih*],记修正后的需求矩阵为[Cih’]。同时,计算针对主配送地j(h) 的剩余装载需求量FFh
FFh = GGn - Flh-1
Step2:对“可调用车辆集”Ph*按第三级优先准则排序,记排序后的“可调用车辆集”为Ph’,记Ph’中各车辆相应装载容量为Ul’(Ul’>Ul+
过程2:模型生成过程
基于过程1的数据驱动,将NPh 转化成为“剩余装载量”极小化为目标,以Ph’和FFh为配载约束且仅以关于车辆选择变量thl 为决策变量的0-1规划模型⒁~⒃。
(0-1)h :min ⒁
St. ≥ FFh ⒂
thl∈{0,1},l∈Pn’ ⒃
过程3:求解过程
Step1:对(0-1)h求解,并基于“最优解”生成的“优选车辆集”Ph,计算优先级最低车辆的“剩余装载量”Flh
Step2:基于需求矩阵[Cih’]和满载要求,先按第三级优先准则,再按第四能优先准则,以数据驱动方式对“优先车辆集”Ph 中的车辆进行配载,生成xhlk 的“最优解”。
(2)值得说明的n个问题:
①关于0-1规划的求解比较成熟,后面讨论
②对优先级最低车辆的剩余装载量的继续配载
5.基于对分搜索(0-1)h的求解过程:(如图所示)
基于上述优化模型,NP问题已经转化为基于优先级循环调用折半查找(对分搜索)的过程
,各类的实现已经编译成 .dll, 该程序中包括一个通用排序类,寻找最优上界的折半查找方法,和Dijkstra算法找配送中心到各配送点最短路径以形成配送路径网络的类.
是测试代码:
class MainEnterPoint
{
public void Default_Input()
{
int r; //列数
r = 7;
int[] a = new int[]{0,2,3,5,99,99,5,
2,0,99,2,99,7,99,
3,99,0,99,5,99,99,
5,2,99,0,3,5,99,
99,99,5,3,0,2,7,
99,7,99,5,2,0,1,
5,99,99,99,7,1,0};
Marx m = new Marx(r, a);
m.Find_way();
Console.WriteLine();
Console.WriteLine("生成路径图:\n");
//---------------------------------------------------------------
web w1 = new web();
ArrayList webWay1 = new ArrayList();
m.Outway(out webWay1);
w1.SetWays(webWay1);
int[] b = new int[r * r];
m.Outdistance(out b);
w1.SetDistance(b);
w1.displayWeb();
int[] s = new int[] { 250, 350 };
Center c = new Center(s);
Console.WriteLine("\n配送中心:\n");
c.displayS();
//------------------------------------------------
//----------测试配送点 ------
int index1 = 1;
DateTime[] ts1 = new DateTime[2];
ts1[0] = new DateTime(2007, 1, 5);
ts1[1] = new DateTime(2007, 2, 13);
int[] rs1 = new int[4] { 6, 3, 5, 7 };
int index2 = 2;
DateTime[] ts2 = new DateTime[2]{
new DateTime(2007,1,5),
new DateTime(2007,3,8)};
int[] rs2 = new int[4] { 8, 7, 1, 0 };
int index3 = 3;
DateTime[] ts3 = new DateTime[2]{
new DateTime(2007,1,5),
new DateTime(2007,2,6)};
int[] rs3 = new int[4] { 18, 7, 4, 3 };
int index4 = 4;
DateTime[] ts4 = new DateTime[2]{
new DateTime(2007,1,6),
new DateTime(2007,2,16)};
int[] rs4 = new int[4] { 7, 6, 14, 13 };
int index5 = 5;
DateTime[] ts5 = new DateTime[2]{
new DateTime(2007,1,15),
new DateTime(2007,3,6)};
int[] rs5 = new int[4] { 17, 2, 0, 1 };
int index6 = 6;
DateTime[] ts6 = new DateTime[2]{
new DateTime(2007,2,5),
new DateTime(2007,4,6)};
int[] rs6 = new int[4] { 0, 16, 2, 3 };
A_point[] points = new A_point[6]{
new A_point(m,index1,ts1,rs1),
new A_point(m,index2,ts2,rs2),
new A_point(m,index3,ts3,rs3),
new A_point(m,index4,ts4,rs4),
new A_point(m,index5,ts5,rs5),
new A_point(m,index6,ts6,rs6)};
//-------------------------------------------------------
//---------------测试车辆 ---------
car[] cars = new car[10]{
new car(1,10),
new car(2,13),
new car(3,18),
new car(4,27),
new car(5,28),
new car(6,20),
new car(7,10),
new car(8,11),
new car(9,17),
new car(10,15)};
//---------------------------------------------------------
NPdeal np = new NPdeal(w1, c, points, cars);
np.run1();
}
public void Self_Input()
{
int r; //列数
Console.Write("请输入点个数(含配送中心点): ");
Int32.TryParse(Console.ReadLine(), out r);
Console.WriteLine("各点分别为: \n");
for (int i = 1; i <= r; i++)
Console.Write("V{0} ", i);
Console.Write("假定第一个点是配送中心");
Console.WriteLine("\n\n输入各点之间的距离(无通径的用相对大整数表示)\n");
int[] a = new int[r * r];
//定义距离矩阵
int da;
for (int i = 0; i < r; i++) //----输入各点之间的距离
{
for (int j = i + 1; j < r; j++)
{
Console.Write("V{0} 到 V{1}的距离是: ", i + 1, j + 1);
Int32.TryParse(Console.ReadLine(), out da);
a[i * r + j] = da;
Console.WriteLine();
}
}
//----完善距离矩阵(距离矩阵其实可以是个上三角矩阵,
//----但为了处理方便,还是将其完整成一个对称阵)-----------
for (int i = 0; i < r; i++)
{
for (int j = 0; j < r; j++)
{
if (i == j)
{
a[i * r + j] = 0;
}
a[j * r + i] = a[i * r + j];
}
}
Marx m = new Marx(r, a); //新建一个找路径对象
m.Find_way(); //生成路径
Console.WriteLine("生成路径图:\n");
web w1 = new web();
ArrayList webWay1 = new ArrayList();
m.Outway(out webWay1);
w1.SetWays(webWay1);
int[] b = new int[r * r];
m.Outdistance(out b);
w1.SetDistance(b);
w1.displayWeb();
//-------路径网络创建完毕--------
//---------------------------------------------------------------
Console.WriteLine("\n输入配送中心货物数目:");
int types;
Int32.TryParse(Console.ReadLine(), out types);
int[] s = new int[types];
Console.WriteLine("输入各种货物库存量:");
for (int i = 0; i < types; i++)
{
Int32.TryParse(Console.ReadLine(), out s[i]);
}
Center c = new Center(s);
Console.WriteLine("\n配送中心:\n");
c.displayS();
//-------配送中心数据输入完毕------------
//---------------------------------------------------------------
int pNo = r - 1;
A_point[] points = new A_point[pNo];
Console.WriteLine("\n录入配送点数据: \n");
for (int i = 0; i < pNo; i++)
{
Console.Write("V{0}点的交货期个数是: ", i + 2);
int times = 0;
Int32.TryParse(Console.ReadLine(), out times);
DateTime[] t = new DateTime[times];
string st;
for (int j = 0; j < times; j++)
{
Console.Write("第 {0} 个交货日期是(输入格式如: 2007/1/1):", j + 1);
st = Console.ReadLine();
t[j] = DateTime.Parse(st);
}
int[] requires = new int[times * types];
int r_index = 0;
for (int js = 0; js < times; js++)
{
Console.WriteLine("第 {0} 个交货期对各货物的需求量为: ",js+1);
for (int ty = 0; ty < types; ty++)
{
Console.WriteLine("货物{0}: ",ty+1);
Int32.TryParse(Console.ReadLine(), out requires[r_index++]);
}
}
points[i] = new A_point(m, i + 1, t, requires);
}
//-----------配送点录入完毕---------------
//----------------------------------------------------------
Console.WriteLine();
Console.WriteLine("输入车辆数目: ");
int carNum = 0;
Int32.TryParse(Console.ReadLine(), out carNum);
car[] cars = new car[carNum];
Console.WriteLine("输入各车载重量: ");
for (int i = 0; i < carNum; i++)
{
int carWeight;
Console.Write("车{0} :", i + 1);
Int32.TryParse(Console.ReadLine(), out carWeight);
cars[i] = new car(i + 1, carWeight);
}
//---------车辆录入完毕------------------------
NPdeal np = new NPdeal(w1, c, points, cars);
np.run1();
}
static void Main(string[] args)
{
Console.WriteLine("****** 基于调运优先准则的物流敏捷调运优化系统 *******\n\n");
MainEnterPoint a = new MainEnterPoint();
Console.WriteLine("按1、测试已有方案\n按2、自行录入方案\n按3、退出");
int chose;
while (true)
{
Int32.TryParse(Console.ReadLine(), out chose);
if (chose == 1)
a.Default_Input();
else if (chose == 2)
a.Self_Input();
else break;
}
}
}
程序流程补充说明
1、本程序省去了一个步骤----“对优先级最低车辆的剩余装载量的继续配载”,
2、关于“当前可调用车辆集”的问题,车辆什么时候可用,什么时候不可用基于以下原理:
在当前配送地的路径上可能有多个点有相同的交货日期,若车X被点P1用了,车的状态就设置为false,即该路径上与P1有相同交货日期的点P2就不能调用车X,而当该路径上所有有相同交货日期的点都配送完成后,车X的状态才会变成可用(true).例如在下图中,
V2 V4 V5 是一条路径上的点,若这3个点有相同的交货日期,按照优先级2,应该先给V5配送,所以,已经被V5所配载装满的车,就不能被V4或V2利用。
3、关于空载率的说明,基于上述第一点,本程序求出的不是“修正后的空载率”,而是每当一条路径上有相同交货日期的点配送完后,就根据车辆配载和剩余容量统计出的空载率。
如下图,V2 V4 V5若有相同交货日期,则对该日期的该路径上的点2,4,5配送完成后,统计一下该路径的空载率。
3、每次配载(即某一个点的一个交货期)完成后,程序会打印出剩余配送点的需求矩阵,
(比较每次当前配送点的需求矩阵就可以看出差别),同时会打印出各车的各项参数,但程序有清屏功能,所以每次看屏幕要把滚动条拉到最上端再往下看。
程序的默认方案如下所示:
路径图: