案例 042 商家自己送一半:店员自送与骑手接力的分工优化

案例 042 商家自己送一半:店员自送与骑手接力的分工优化

摘要:门店 1 名店员(离店窗 28 min)与 1 名骑手(班次 80 min)共同消化 10 单。本文把"哪些单店员送、哪些单骑手送"写成指派—双路径 MILP:\(x_{i,v}\) 定归属、\(y_{ij,v}\) 定弧、时间大 M 递推,店员窗与骑手班次各一条硬约束。三种分工对比:全骑手 41.07 元(超班 7.1 min、6 单超时)、固定规则 25.37 元、优化分工 22.65 元。优化解让店员绕西侧一圈(O4→O5→O2→O1)、骑手走东北走廊,比全骑手省 18.42 元。1024 种分工全枚举(Held-Karp 精确路径)验证 MIP 最优,并给出时间窗与班次两条灵敏度曲线。

关键词:即时配送;运力分工;指派—路径;时间窗;Gurobi

1 问题提出

1.1 问题是什么

17:00,连锁品牌门店有两拨运力:1 名店员(17:00—17:28 可以离店,之后必须回店接晚市)和1 名驻店骑手(班次到 18:20,共 80 min),10 单已经打包好堆在出餐口。题目给的规则很朴素:3 km 内、或低价单由商家自送,其余交给骑手。真按规则走会撞上两个数:店员只有一个离店窗,骑手只有一个班次。自送不是"免费运力",它花的是店员离店的分钟数;而骑手每多接一单,除了多跑路,还要多一次 2 min 的店门口交接。

数据见表 1。10 单沿不同方向铺开:O1、O3、O6—O10 基本在同一条东北走廊上,O2、O4、O5 分别拐向西南、西北、正南,是三条孤立方向。几何结构决定了分工的答案:走廊上的单让骑手顺路带走最便宜,孤立方向的单才是店员该去啃的。

表 1 十单数据(方位角自正东逆时针;时限 = 20 + 11 × 距离)

订单 送达点 方位 / 度 距店 / km 承诺时限 / min 配送费 / 元 优化归属
O1 体育西横街 80 0.6 24 6.5 店员
O2 杨箕小区 200 0.9 34 7.0 店员
O3 五羊新城 110 1.1 38 7.5 骑手
O4 流花路口 300 1.4 33 8.0 店员
O5 荔湾广场 250 1.9 46 9.5 店员
O6 天河北 60 2.2 45 9.0 骑手
O7 燕塘地铁口 75 2.7 44 10.0 骑手
O8 同和路口 45 3.2 58 10.5 骑手
O9 白云大道 85 3.7 63 11.0 骑手
O10 嘉禾望岗 30 4.5 66 12.0 骑手

核心问题:把 10 单分成"店员若干单 / 骑手若干单"两类,共 \(2^{10}=1024\) 种分法。难的不是"分几单",而是分哪几单:店员的时间窗只够绕 28 min、最多 4 单,选错一单就白跑。

图 1 优化分工下的空间结构:店员环线(橙)与骑手走廊(蓝)

1.2 为什么要优化

  1. 全骑手跑不完:10 单串成一条链,骑手 87.1 min,超出 80 min 班次 7.1 min,按 1.5 元/min 折算 10.65 元;还有 6 单晚于承诺时限。
  2. 按距离拍板会选错单:最近的 3 单是 O1, O2, O3,其中 O1、O3 就在骑手走廊上——店员把它们拿走,等于让骑手为 O4、O5 两个孤立方向单独绕一趟,骑手仍然要跑 73.3 min。
  3. 优化分工要同时满足两个容量:店员 28 min 的离店窗与 4 单的上限、骑手 80 min 的班次。只用一条规则拍板,必然有一头被撑破。

图 2 十单的距离—时限分布(气泡=配送费,颜色=优化后的归属)

1.3 Gurobi 如何求解

建模→预处理→分支定界→校验→参数扫描。指派变量 \(x_{i,v}\) 与弧变量 \(y_{i,j,v}\) 一起进模型,时刻用大 M 递推;由于弧上行驶时间严格为正,时刻递推天然排除子回路,不需要再加 MTZ 或 DFJ 割——正好绕开题目提醒的"交接点复制节点导致子回路"的坑。求解后用 Held-Karp 动态规划把 1024 种分工的精确路径全部算了一遍,既校验 MIP,又给图 8、图 9 提供完整解空间。

2 数学模型

2.1 符号与参数

订单 \(i,j\in\{1,\dots,10\}\),车辆 \(v\in\{0,1\}\)(\(0\) 店员、\(1\) 骑手),\(0\) 为门店。\(d_{ij}\) 弧长(km),\(\tau^{v}_{ij}\) 弧上行驶时间,\(s=1.5\) min 停靠,\(h=2\) min/单 交接,\(D_i\) 承诺时限,\(C_i\) 送达时刻,\(E_v\) 回店/收工时刻。\(c_r=0.6\)、\(c_s=0.45\) 元/km,\(b=2\) 元/单 交接费,\(\omega=1.5\) 元/min 超班折算,\(W=28\) min,\(T=80\) min,\(K=4\)。

2.2 目标函数

\[\min\; c_r\sum_{(i,j)}d_{ij}y_{ij,1}+b\sum_{i}x_{i,1}+c_s\sum_{(i,j)}d_{ij}y_{ij,0} \tag{1} \]

三项依次是骑手里程、交接费、店员自送。店员每公里比骑手便宜(无平台抽成),但店员的时间窗与单量上限很紧,"便宜"不等于"该多送"。

2.3 约束条件

每单恰好归一拨,店员至多 \(K\) 单:

\[\sum_{v}x_{i,v}=1,\qquad \sum_{i}x_{i,0}\le K \tag{2} \]

流量守恒与门店出入度(\(z_v\) 表示该车是否出车):

\[\sum_{j\ne i}y_{ij,v}=x_{i,v},\qquad \sum_{j\ne i}y_{ji,v}=x_{i,v},\qquad \sum_{j}y_{0j,v}=\sum_{j}y_{j0,v}=z_{v}\le 1 \tag{3} \]

骑手出发前按单交接,店员不产生交接:

\[\sigma_0=0,\qquad \sigma_1=h\sum_{i}x_{i,1} \tag{4} \]

到达时刻递推:

\[C_{j}\ge \sigma_{v}+\tau^{v}_{0j}-M(1-y_{0j,v}),\qquad C_{j}\ge C_{i}+s+\tau^{v}_{ij}-M(1-y_{ij,v}) \tag{5} \]

两个时间上限:店员必须在离店窗内回店,骑手必须在班次内收工:

\[E_{v}\ge C_{i}+s+\tau^{v}_{i0}-M(1-y_{i0,v}),\qquad E_{0}\le W,\quad E_{1}\le T \tag{6} \]

\[x_{i,v},y_{ij,v},z_{v}\in\{0,1\},\qquad C_{i},E_{v},\sigma_{v}\ge 0 \tag{7} \]

式 (5) 中 \(\tau^{0}_{ij}=3.2d_{ij}\)、\(\tau^{1}_{ij}=3.0d_{ij}\)(店员 18.75 km/h、骑手 20 km/h);\(M=300\) 取"最长班次 + 最长回路"的量级,不用 \(10^{6}\)。

规模与性质:0-1 变量 242 个、约束 281 条、非零 1192 个;Gurobi 墙钟 0.57 s、gap 0.0e+00。模型是带容量与两类时间上限的双车指派—路径问题:给定归属后两侧各是一个小规模 TSP(\(n\le 10\)),所以难在组合而不在路径,\(2^{10}\) 的全枚举可以精确复核。

3 Gurobi 求解实现

3.1 建模要点

x = m.addVars(range(1, N+1), [0, 1], vtype=GRB.BINARY)      # 归属
y = m.addVars(..., vtype=GRB.BINARY)                        # 弧 (i,j,v)
m.addConstr(st[1] == 2.0 * quicksum(x[i, 1] for i in range(1, N+1)))   # 交接前置
m.addConstr(T[j] >= T[i] + 1.5 + tau[v][i, j] - M * (1 - y[i, j, v]))
m.addConstr(en[0] <= 28); m.addConstr(en[1] <= 80)           # 店员窗 / 骑手班次

两个实现细节。其一,交接时间放在出发端而不是弧上:\(\sigma_1=2\sum_i x_{i,1}\) 是线性的,把它并进"门店 → 首单"的弧,比给每条弧单独算交接更省变量,也避免"交接点复制节点"带来的子回路。其二,用时刻递推替代 MTZ:弧上时间严格为正,任何环都要求 \(C_i>C_i\),天然不可行,次序变量整段可以省掉。

3.2 求解结果

表 2 三种分工的指标对比(全骑手按 1.5 元/min 折算超班)

方案 店员送 骑手送 骑手里程 / km 店员里程 / km 骑手时长 / min 超时 / 单 总成本 / 元
全骑手 0 10 17.37 0.00 87.1 6 41.07
固定规则 3 7 16.27 3.57 73.3 2 25.37
优化分工 4 6 13.05 6.26 60.2 2 22.65

优化分工:店员送 O1, O2, O4, O5,骑手跑 6 单走廊,总成本 22.65 元,比全骑手省 18.42 元(45%),比固定规则省 2.72 元。固定规则在 54 种可行分工里排第 10 位——它不算差,但把 85% 的可省空间留在了桌上。

图 3 三种分工的成本分解(交接费与超班折算才是差距来源)

4 结果分析

4.1 结构与过程

图 1 的两条线几乎没有交叉:店员先向西北到 O4、南下 O5、折向 O2,最后回门口的 O1,走一个闭环;骑手从 O6 一路沿东北走廊向北。分工的本质是把"方向"分开,而不是把"距离"分开——店员绕的三个点彼此相距 1—2 km,但都在门店西侧半圆内,一圈 6.26 km、26.0 min,刚好卡进 28 min 窗口。

图 2 里十单围绕时限线上下摆动,单看"单点直达"每一单都来得及;问题只出在串行上——全骑手要把 10 单串成一条链,最后一单的到达时刻被推到 83.8 min。图 4 是骑手累计里程曲线,三条线终点差得不小(17.37 / 16.27 / 13.05 km),斜率差得更远:固定规则要为 O4、O5 两个孤立方向各拐一次,曲线出现两段"空跑";优化分工把这两段整体挪给了店员,骑手曲线几乎是单调北上的直线。

图 4 三种分工下骑手的累计里程与推进节奏

4.2 灵敏度:店员的时间窗是真正的瓶颈

图 5 扫店员离店窗 \(W\) 从 20 到 44 min。\(W=20\) 时店员只装得下 3 单,总成本 25.37 元——正好退化成固定规则的水平;放到 28 min 时降到 22.65 元(自送 4 单);再往上放曲线完全变平,因为单量已经顶到 \(K=4\) 的上限,加时间也没用。先降后平说明:时间窗与单量是两个独立的闸门,先到哪个哪个说了算,本案卡在单量上。图 6 把窗口与自送单价同时扫色块自左向右变浅(窗口放开、成本下降),自上而下变深(店员越贵越不该多送);最右两列几乎同色,再次印证单量闸门先关。本案星标(28 min,0.45 元/km)落在折角处——店员单价只比骑手低 25%,这个差价就是自送的经济理由;单价涨到 0.75 元时,最优解仍留 3—4 单给店员,但成本已回到 24.53 元。

图 5 店员离店时间窗对最优成本与自送单数的影响

图 6 时间窗与自送单价的二维灵敏度(色块=最优总成本)

4.3 第三维与前沿

图 7 把单量上限 \(K\) 从 1 放到 5。\(K=1\) 时店员只能拿 1 单,成本 30.56 元;\(K=3\) 时 24.23 元;\(K=4\) 时 22.65 元;\(K=5\) 不再变化——第 4 单正好是边际收益归零的位置(再多的单塞不进 28 min 的窗)。这条阶梯把"该给店员几单"从经验判断变成了边际比较。图 8 把 1024 种分工全部画在"骑手时长—总成本"平面上。可行点(54 个)呈一条向右上的斜带:想让骑手少跑,就得让店员多送,成本先降后升。阴影区是超过 80 min 班次的分工,全骑手(叉)正落在阴影里——它不是"贵一点",而是"排不进班次"。

图 7 店员单量上限对最优成本与自送单数的影响

图 8 成本—骑手时长前沿与超班不可行区(阴影)

4.4 分布与边际

图 9 是 54 种可行分工的成本分布:均值 27.03 元、最好 22.65、最差 30.56。优化分工落在最左端,固定规则在第 10 位。"随便分一分"的平均代价比最优高 4.38 元——这正是规则拍板与算一遍的差距。图 10 是对最优解逐单"改判"的边际:把某一单从店员挪给骑手(或反向),成本变多少。10 单里只有 4 单的改判可行,且全部为负收益(+1.58 到 +3.62 元);另外 6 单(骑手侧的 O6—O10 与 O3)一改判就不可行——店员窗口已经装满。也就是说,优化解不是"碰巧选了 4 单",而是被两个闸门同时顶住的唯一组合。

图 9 可行分工的总成本分布与三种方案的位置

图 10 逐单改判的边际成本(标注当前归属,不可行即窗口/班次已满)

5 结论

  1. 全骑手不可行:10 单串一条链,骑手 87.1 min,超班 7.1 min、6 单超时,折算后 41.07 元。这不是"贵一点",是排不进班次。
  2. 按距离拍板的规则会选错单:最近 3 单里有 2 单在骑手走廊上,店员拿走它们等于让骑手为孤立方向单独绕路,总时长 73.3 min、成本 25.37 元,比最优贵 2.72 元。
  3. 优化分工:店员送 O1, O2, O4, O5(6.26 km、26.0 min),骑手跑 6 单走廊(13.05 km、60.2 min),总成本 22.65 元,比全骑手省 18.42 元(45%)。
  4. 分工的正确维度是方向,不是距离:店员的时间窗适合"扫一个扇区",骑手的班次适合"走一条走廊";判据是边际成本 \(\Delta=b+c_r\Delta d_r-c_s\Delta d_s\),而不是"3 km 以内"。
  5. 两个闸门先到先算:店员侧受 \(W\) 与 \(K\) 双重约束(本案卡在 \(K=4\),图 5、图 7 同时给出这个结论),骑手侧受 \(T\) 约束(本案留 19.8 min 余量)。加运力之前先看哪个闸门先关,否则加了也白加。

参考文献

[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.

[5] Toth P, Vigo D. Vehicle Routing: Problems, Methods, and Applications[M]. 2nd ed. Philadelphia: SIAM, 2014.

[6] Held M, Karp R M. A dynamic programming approach to sequencing problems[J]. Journal of the Society for Industrial and Applied Mathematics, 1962, 10(1): 196-210.

posted @ 2026-11-11 18:01  小青蛙电气  阅读(2)  评论(0)    收藏  举报