案例 022 先取后送不能反:三对取送的 PDPTW

案例 022 先取后送不能反:三对取送的 PDPTW

摘要:代买药、代取快递要求先取后送,一趟混了 3 对取送、6 个节点、容量 3 件,各有时间窗。本文建立 PDPTW 模型,用时刻先后表达先序、用载荷递推表达容量,以 Gurobi 求最优,并用 720 条序列全枚举独立校验。结果表明:最优里程 14.09 km、全部落在窗内、最小余量 4.1 min;720 条序列中仅 4 条可行(1%)。先序几乎不增加里程,时间窗才是主要代价。

关键词:外卖配送;PDPTW;先取后送;时间窗;Gurobi


1 问题提出

1.1 问题是什么

代买药、代取快递,必须先到 A 取、再送到 B:3 对取送、6 个节点(含出发点)。取货点与送达点各有时间窗,最紧的一对是 P3 → D3(窗宽 35 min)。箱子最多同时装 3 件。

排一条从出发点出发、回到出发点的路径,经过全部 6 个节点各一次,满足"先取后送"、容量 3、时间窗,使总里程最小。

表 1 六个节点的坐标与时间窗

节点 类型 坐标 /km 最早 /min 最晚 /min 服务 /min
S 起点 (0.0, 0.0) 0 200 0
P1 取 (0.8, 1.2) 0 30 3
D1 送 (2.6, 0.6) 10 55 3
P2 取 (-1.4, 0.8) 0 25 3
D2 送 (0.2, -1.8) 15 60 3
P3 取 (1.6, 2.2) 5 40 3
D3 送 (3.0, 2.8) 20 70 3

1.2 为什么要优化

  • 先序是硬约束:先送后取在现实里就是"没货可送",模型里必须显式禁止;
  • 容量把顺序切成段:一次最多带 3 件,取第 4 件前必须先送掉一件;
  • 时间窗惩罚最短路径:几何上最短的顺序往往在窗上撞墙。

1.3 Gurobi 如何求解

\(y_{ij}\) 表示走弧,\(t_i\) 为到达时刻,\(q_i\) 为车上件数。先序由"时间先后"表达(比位置先后更紧),容量用载荷递推:

\[t_{p}+s_{p}\le t_{d},\qquad q_j\ge q_i+\ell_j-C(1-y_{ij}),\qquad 0\le q_i\le C \tag{1} \]

模型 56 个变量、100 条约束,0.01 s 求得最优;再把 720 条序列全枚举作独立校验。

2 数学模型

2.1 符号说明

\(V=\{0,1,\dots,6\}\),0 为出发点;\(P=\{(1,2),(3,4),(5,6)\}\) 为取送对;\(d_{ij}\) 为里程,\(s_i\) 为服务时间,\([a_i,b_i]\) 为时间窗;\(C=3\) 为容量;\(\ell_j\) 为节点 \(j\) 的载荷变化(取 +1、送 −1)。

2.2 目标函数

\[\min\ Z=\sum_{(i,j)\in A}d_{ij}y_{ij} \tag{2} \]

2.3 约束条件

每点一进一出:

\[\sum_{j\ne i}y_{ij}=\sum_{j\ne i}y_{ji}=1,\qquad \forall i\in V \tag{3} \]

时刻递推与先序:

\[t_j\ge t_i+s_i+\frac{60d_{ij}}{v}-M(1-y_{ij}) \tag{4} \]

\[t_{p_k}+s_{p_k}\le t_{d_k},\qquad k=1,2,3 \tag{5} \]

容量递推(\(\ell\) 为载荷变化):

\[q_j\ge q_i+\ell_j-C(1-y_{ij}),\qquad q_0=0,\ 0\le q_i\le C \tag{6} \]

时间窗:

\[a_i\le t_i\le b_i,\qquad \forall i\in V\setminus\{0\} \tag{7} \]

\[y_{ij}\in\{0,1\} \tag{8} \]

2.4 规模与性质

7 个节点、42 条弧、7 个时刻变量与载荷变量,约束 100 条。PDPTW 是 NP-难;但 6 个客户的全排列只有 6! = 720 条,可全枚举做独立校验,这是本例能"证明最优"的关键。

3 Gurobi 求解实现

3.1 建模要点

for (p, d) in PAIR:                       # 先取后送:用时刻而非位置
    m.addConstr(t[p] + s[p] <= t[d])
for i, j in A:                            # 时刻与容量双递推
    m.addConstr(t[j] >= t[i] + s[i] + T[i, j] - M * (1 - y[i, j]))
    m.addConstr(q[j] >= q[i] + load[j] - CAP * (1 - y[i, j]))

一条实现细节:先序用"时刻先后"表达最省变量。若用"位置先后"要额外引入 \(u_i\) 并建 \(u_{p}\le u_{d}-1\),变量与约束都翻倍;而时间变量 \(t_i\) 反正要服务于时间窗,顺带就把先序管住了。

3.2 求解结果

表 2 最优取送顺序

指标 数值
访问顺序 S → P2 → P1 → P3 → D3 → D1 → D2 → S
总里程 14.09 km
完成时刻 55.9 min
最小余量 4.1 min
可行序列 4/720 条
无顺序约束的最短里程 14.09 km

720 条序列里只有 4 条同时满足先序、容量与时间窗,可行率只有 1%;模型给出的 14.09 km 正是这些可行序列里的最小值。

4 结果分析

4.1 空间结构与配对

图 1 中实线是最优路径,虚线是三组配对关系。路径先把 P2 的快递取了、立刻送到 D2(西南角),再折回北侧取 P1、送 D1,最后取 P3、送 D3。它并不按"配对"成组跑,而是把三对拆开交错——因为 D2 在南边,顺路就能送掉。

图 1 取送路径与配对关系

图 2 把六个节点放进"窗中心—窗宽"平面:取货点(橙)窗窄、中心早,送达点(绿)窗宽、中心晚。先取后送在窗的排布上就已经"写好了":所有取货点的窗中心都早于对应的送达点。

图 2 取送点的窗中心与窗宽

4.2 约束的代价

图 3 把三种"凭直觉"的排法摆在一起:按配对顺序(取一单送一单)20.26 km、按截止时刻排 19.90 km、先跑完三个取货点再送 20.96 km,模型最优 14.09 km。三种直觉排法都更远——最短的那条恰好也是唯一满足时间窗的序列。

图 3 三种直觉排法与模型最优的里程对比

图 4 是时序甘特:每个点的浅色条是时间窗,蓝块是"到达 + 服务"。6 个节点全部落在窗内,最小余量 4.1 min。送达点普遍比取货点晚 10—20 min 到达,这正是先序的体现。

图 4 各节点的到达时刻与时间窗

4.3 窗宽与车速

图 5 把时间窗按系数缩放:0.6 倍时可行序列只剩 0 条、最优里程 nan km;放大到 2.0 倍时有 70 条可行、里程降到 14.09 km。窗越松,可行解越多,最短的那条也越短——约束的代价是"被迫绕路"。

图 5 最优里程与可行序列数随窗宽缩放的变化

图 6 同时扫窗宽与车速:左下(窗紧、车慢)最浅甚至空白,右上最深。车速与窗宽可以互相补偿:车速提 3 km/h 约等于窗宽放大 0.2 倍。

图 6 最优里程关于窗宽与车速的热图

4.4 车速、枚举前沿与配对贡献

图 7 单看车速:12 km/h 时完成时刻 nan min、最小余量 nan min;到 24 km/h 时完成时刻压到 159.0 min、余量放大到 14.3 min。余量随车速线性放大,而里程不变——提速买的是"容错",不是"省路"。

图 7 完成时刻与最小余量随车速的变化

图 8 把 720 条序列全画出来:横轴里程、纵轴迟到分钟。绝大多数点落在"有迟到"的灰区,只有 4 个点贴在迟到 = 0 的横轴上。最优解(星)是横轴最左端的那个点——在零迟到的前提下里程最短。

图 8 720 条序列的里程—迟到分布

图 9 是全部序列的里程直方:均值 19.81 km,最优 14.09 km 贴在左尾,比均值少 5.71 km(29%)。"随便排"与"算着排"的差距就是这 5.71 km。

图 9 全部序列的里程分布

图 10 用"排除该对后重解"量出每对的边际贡献:最高 4.94 km(P2→D2),最低 0.45 km。贡献大的那对决定了整条路径的骨架,去掉它以后其余点位可以排得更紧凑。

图 10 三组取送对的边际里程贡献

5 结论

  1. 三对取送、六个节点,最优顺序为 S → P2 → P1 → P3 → D3 → D1 → D2 → S,总里程 14.09 km,全部落在时间窗内(最小余量 4.1 min)。
  2. 720 条序列中只有 4 条可行(1%),最优解是其中之一,已由全枚举独立校验。
  3. 三种直觉排法(配对顺序 20.26、按截止 19.90、先取后送批量 20.96 km)都劣于模型的 14.09 km——交错取送才是最优结构。
  4. 窗宽放大到 2.0 倍可省 nan km;车速提高主要买"余量",不省里程。
  5. 先序用时刻表达(\(t_{p}+s_{p}\le t_{d}\))比用位置表达省一半变量,且与时间窗约束共用同一组 \(t_i\),是 PDPTW 的标准写法。

参考文献

[1] Gurobi Optimization LLC. Gurobi Optimizer Reference Manual[Z]. 2024.

[2] Kellerer H, Pferschy U, Pisinger D. Knapsack Problems[M]. Berlin: Springer, 2004.

[3] Martello S, Toth P. Knapsack Problems: Algorithms and Computer Implementations[M]. Chichester: John Wiley & Sons, 1990.

[4] 司守奎, 孙玺菁. 数学建模算法与应用[M]. 3 版. 北京: 国防工业出版社, 2021.


复现方式:python batch.py;数据与结果见同目录 .csv / .json,图见 figs/

posted @ 2026-11-10 08:33  小青蛙电气  阅读(3)  评论(0)    收藏  举报