案例 052 商家取消单,骑手白跑

案例 052 商家取消单,骑手白跑

摘要:骑手骑到店门口,商家一句“单子取消了”,油钱、时间、后面的派单全部作废。本文把 12 起“到店即取消”事件放进一个 220 min 的晚高峰,比较立即转接新单、原地等待平台补派、空驶回商圈三种应对的回收与耗时,建立多选择背包模型。基准账:原单应得 127.4 元、沉没成本 36.7 元,平台补偿合计 31.5 元,只能覆盖沉没成本的 86%。优化调度把净损失压到 36.9 元,比全转接的 55.3 元少亏 18.4 元;而“全等待”与“全回商圈”都要超时 28 min 和 26 min,根本跑不完。补派的临界等待时长平均 9.5 min,平台实际补派等待 7.5 min,只有 7 起事件等得起;5 起事件的补偿低于临界值,平均缺 1.51 元。

关键词:订单取消;沉没成本;多选择背包;时间影子价格;临界等待;外卖派单


1 问题提出

1.1 问题是什么

晚高峰 220 min,12 起订单在骑手到达商家后被取消。此刻三件事已经发生且不可逆:已骑的 66.8 min 空驶(折 36.7 元)、原单 127.4 元的配送费、以及被挤掉的其他派单机会。平台按单补 2.6 元左右,杯水车薪。

摆在骑手面前只有三条路:立即抢一张新单(快,但新单往往更近更便宜)、原地等平台补派(补派单通常更远更贵,但要等)、空驶回商圈(回熟悉的点位,路上白耗)。表 1 给出 12 起事件的完整档案。

表 1 12 起到店取消事件的沉没时间、补偿、补派条件与三种策略净回收(金额单位:元)

事件 距离 km 沉没 min 补偿 补派率 补派等待 转接回收 等待回收 回圈回收 模型选定
C01 2.8 7.4 2.0 0.55 8 8.60 9.36 6.62 转接
C02 1.6 4.7 3.5 0.72 6 9.40 11.78 7.34 等待
C03 3.2 8.2 1.5 0.45 12 8.20 6.99 6.38 转接
C04 0.9 3.2 4.0 0.85 4 9.80 13.48 7.76 等待
C05 2.1 5.8 2.5 0.65 7 8.80 10.67 7.04 等待
C06 1.2 3.8 3.0 0.78 5 9.60 12.08 7.58 等待
C07 3.0 7.8 1.0 0.50 13 8.40 6.91 6.50 转接
C08 2.4 6.5 2.0 0.60 9 8.60 9.38 6.86 转接
C09 0.7 2.7 4.5 0.88 3 10.00 14.08 7.88 等待
C10 1.9 5.4 2.5 0.68 6 9.20 10.80 7.16 等待
C11 2.6 6.9 1.5 0.48 12 8.50 6.92 6.74 转接
C12 1.4 4.3 3.5 0.75 5 9.70 12.05 7.46 等待

(表中“模型选定”是计入班次时间后的结果,与单起事件的最优回收可能不同。)单看回收,等待平均最高(补派期望 9.1 元再加 2.6 元补偿),转接次之(9.1 元),回商圈最差(7.1 元);但单看耗时,等待平均要多花 7.5 min,回商圈要多骑 5.0 min,钱和时间正好反着走。

1.2 为什么要优化

沉没成本的第一课是“不该进决策”,第二课是“必须进账本”。空驶那 66.8 min 无论选哪条路都收不回来,所以它不出现在目标函数里;但它决定了“这一趟到底亏多少”,所以它必须出现在净损失里。把这两件事分开,才不会出现“已经骑了 8 分钟,不走完更亏”的谬误。

第二,三种策略的耗时差异会把班次撑爆。全等待要 248 min、全回商圈要 246 min,都超过 220 min,意味着必须挑着等。等几次、等哪几次,是一道有约束的选择题,不是意志力问题。

第三,谈判需要一个数。平台问“补多少你们才愿意等”,答案应是临界补偿 \(b^{*}_{i}\),而不是情绪。

1.3 Gurobi 如何求解

每起事件 3 个 0-1 变量,共 36 个 0-1 变量、12 条“必须选一个”的约束、1 条班次时间约束,是标准的多选择背包。规模极小,单次求解毫秒级;全部参数扫描共 40 余次求解,墙钟 1 s 以内。真正的信息量在时间约束的对偶价格 \(\lambda\):它把“一分钟值多少钱”直接读出来,是临界等待与临界补偿的分母。

2 数学模型

2.1 符号说明

\(\mathcal{I}\) 为取消事件集合(\(|\mathcal{I}|=12\)),\(\mathcal{K}=\{A,B,C\}\) 为转接、等待、回商圈三种应对。\(w^{0}_{i}\) 为原单配送费,\(a_{i}\) 为已空驶时间,\(c_{s}\) 为时间成本(元/min),\(b_{i}\) 为取消补偿,\(p_{i}\) 为补派成功率,\(w_{i}\) 为补派单价值,\(\omega_{i}\) 为补派等待,\(u_{i}\) 为转接单价值,\(g_{i}\) 为转接等待,\(r_{i}\) 为空驶回商圈时间,\(S_{i}\) 为新单服务时长,\(T\) 为班次时长,\(\rho\) 为超时罚系数,\(\lambda\) 为时间影子价格。决策变量 \(z_{ik}\in\{0,1\}\)。

2.2 目标函数

\[\max\ \sum_{i\in\mathcal{I}}\sum_{k\in\mathcal{K}}v_{ik}\,z_{ik}\tag{1} \]

每起事件只选一条路,目标是把三条路的回收加总最大化。注意式 (1) 里没有 \(c_{s}a_{i}\)——沉没成本与本决策无关。

2.3 约束条件

\[\sum_{k\in\mathcal{K}}z_{ik}=1,\qquad z_{ik}\in\{0,1\},\quad i\in\mathcal{I}\tag{2} \]

\[\sum_{i\in\mathcal{I}}\sum_{k\in\mathcal{K}}t_{ik}\,z_{ik}\le T\tag{3} \]

式 (2) 是互斥选择,式 (3) 是班次硬约束。三条路的回收与耗时分别为:

\[v_{iA}=u_{i},\qquad t_{iA}=g_{i}+S_{i}\tag{4} \]

\[v_{iB}=b_{i}+p_{i}w_{i}-c_{w}\omega_{i},\qquad t_{iB}=\omega_{i}+S_{i}\tag{5} \]

\[v_{iC}=u_{0}-c_{k}r_{i},\qquad t_{iC}=r_{i}+g_{0}+S_{i}\tag{6} \]

式 (4) 转接:收益是现成新单的价值,代价只有等单与送单;式 (5) 等待:收益是补偿加“补派成功率 × 补派单价值”,代价是等待时间与等待的机会成本 \(c_{w}\omega_{i}\);式 (6) 回商圈:拿商圈平均单 \(u_{0}\),但要先白骑 \(r_{i}\) 分钟,按 \(c_{k}\) 元/min 计空驶成本。三式的差别只在“用时间换钱”的汇率不同,这正是要算的东西。

净损失的账本另算:

\[L=\sum_{i\in\mathcal{I}}\left(w^{0}_{i}+c_{s}a_{i}\right)-\sum_{i\in\mathcal{I}}\sum_{k\in\mathcal{K}}v_{ik}z_{ik}+\rho\left[\sum_{i}\sum_{k}t_{ik}z_{ik}-T\right]^{+}\tag{7} \]

式 (7) 才是骑手真正心疼的数:原单该拿的、已经烧掉的、以及超时的加班罚,减去能收回来的。\([\cdot]^{+}\) 让“全等待”“全回商圈”这类超时方案可以比较,但要打上不可行的标记。

沉没成本的无关性可以直接看出来:

\[\max\ \sum_{i}\sum_{k}v_{ik}z_{ik}\ \equiv\ \max\ \sum_{i}\sum_{k}\left(v_{ik}-c_{s}a_{i}\right)z_{ik}\tag{8} \]

右端对 \(z\) 的偏导与 \(a_{i}\) 无关,所以“已经骑了多久”不改变最优选择,只改变亏多少。这就是沉没成本唯一的正确用法:进账本,不进目标。

\[\omega^{*}_{i}=\frac{b_{i}+p_{i}w_{i}-u_{i}+\lambda g_{i}}{c_{w}+\lambda},\qquad \lambda=-\frac{\partial \Phi}{\partial T}\tag{9} \]

\[b^{*}_{i}=u_{i}-p_{i}w_{i}+\left(c_{w}+\lambda\right)\omega_{i}-\lambda g_{i}\tag{10} \]

\[\Phi(T)=\max\left\{\sum_{i}\sum_{k}v_{ik}z_{ik}:\ \text{式 (2), 式 (3)}\right\}\tag{11} \]

式 (9) 由“等与转接等价”解出:\(\omega^{*}_{i}\) 是临界等待时长,等待超过它就转接。分母里的 \(\lambda\) 是式 (11) 值函数对班次时长的导数,即“多给一分钟能多赚多少钱”。忽略 \(\lambda\) 是把时间当免费,会把所有事件都判成“值得等”。 式 (10) 是同一等式对 \(b_{i}\) 的反解,即临界补偿。

2.4 规模与性质

36 个 0-1 变量、13 条约束,是教科书级的多选择背包;LP 松弛的对偶给出 \(\lambda\),MILP 分支定界给整数解。因为每条路的耗时都含 \(S_{i}\),模型对 \(S_{i}\) 不敏感,真正起作用的是“额外占用的分钟数”。

3 Gurobi 求解实现

3.1 建模要点

核心四行与式 (1)—(3) 一一对应:

z = m.addVars(N, 3, vtype=GRB.BINARY, name="z")
m.addConstrs((gp.quicksum(z[i, k] for k in range(3)) == 1 for i in range(N)))
tc = m.addConstr(gp.quicksum(T[i, k] * z[i, k] for i in range(N) for k in range(3)) <= T)
m.setObjective(gp.quicksum(V[i, k] * z[i, k] for i in range(N) for k in range(3)), GRB.MAXIMIZE)

对偶价格这样取:把同一模型改成 GRB.CONTINUOUS 再解一次,读 tc.Pi。最大化问题里“小于等于”约束的 Pi 非负,直接取 \(\lambda=-\)tc.Pi,本案得 0.156 元/min。不取对偶而直接把式 (9) 的 \(\lambda\) 设 0,临界等待会从 9.5 min 虚高到 14.8 min,几乎每起都判“值得等”——这就是白等的来源。

3.2 求解结果

表 2 四种方案在 220 min 班次内的回收、净损失与超时(金额单位:元)

方案 占用 min 超时 min 班次回收 净损失 等待/回圈 起 是否可行
全转接 200 0 108.8 55.3 0 可行
全等待 248 28 124.5 73.2 12 超时
全回商圈 246 26 85.3 110.5 12 超时
优化调度 217 0 127.2 36.9 7 可行

四种方案的排序是:优化 36.9 < 全转接 55.3 < 全等待 73.2 < 全回商圈 110.5。全转接可行但把钱让掉了 18.4 元;全等待回收最高,可它要 248 min,超时 28 min,按 1.2 元/min 计罚后反而更亏;全回商圈两头不讨好。优化方案在 217 min 内跑完,只用 7 次等待、0 次回商圈,剩下的全部转接——等得起才等,等不起立刻走。

4 结果分析

图 1 一起取消事件下三种应对方式的时间结构(C01)

4.1 三种应对的时间结构 图 1 用 C01 的事件画了三条时间轴。三种应对的沉没空驶段完全相同(灰色,7 min),差别从中段开始:转接只花 3 min 等单,等待要占 8 min,回商圈得先骑 7 min 再等 2.4 min。同一段沉没之后,三条路的中段长度差出三倍,而尾段服务时长完全一样——选择其实只在中段发生。

图 2 12 起事件的沉没时间与取消补偿(气泡为补派等待)

4.2 沉没时间与补偿的分布 图 2 横轴沉没时间、纵轴补偿、气泡是补派等待、颜色是补派成功率。补偿与沉没时间几乎不相关:最远的 C03 沉没 8.2 min 只补 1.5 元,最近的 C09 沉没 2.7 min 却补了 4.5 元。平台的补偿更像“随机安慰”,而不是“按损失定价”——这本身就是可谈判的空间。

图 3 四种方案的班次净损失与超时情况

4.3 四方案净损失 图 3 是核心对比。全转接 55.3 元、全等待 73.2 元(阴影为超时部分)、全回商圈 110.5 元、优化 36.9 元。优化相对全转接省下 18.4 元,相当于每起事件少亏 1.5 元;而两种“等”和“回”的方案在 220 min 里根本排不开。

图 4 三种方案的累计回收与班次上限

4.4 累计回收 图 4 把三条路线摊在时钟上。优化与全转接在前 100 min 几乎重合,分叉出现在中段:优化在 C04、C09 这类高成功率的点上停一下,全转接一律快走。最上方的点线是“原单全部完成”的基准,最终停在 127.4 元;优化停在 127.2 元,与基准只差 0.2 元——回收几乎追平,但沉没的 36.7 元再也回不来,这就是 36.9 元净损失的来源。全等待那条线在中途就冲过了 220 min 的竖线——它多赚的钱是靠加班换的。

图 5 补偿倍数灵敏度:净损失与等待策略单数

4.5 主灵敏度:补偿倍数 图 5 让补偿从 0 倍扫到 3 倍。净损失从 55.3 元单调降到 -10.1 元,降幅 65.4 元;等待单数从 0 起跳到 7 起,呈 2 级阶梯。关键在斜率:补偿总额每多 1 元,净损失只降 0.69 元——补偿是纯转移支付,它不能把白跑变成不白跑,只能把损失在骑手和平台之间挪一挪。

图 6 补偿倍数 × 补派等待缩放的净损失热图

4.6 二维:补偿 × 补派等待 图 6 是 4 行 5 列热图。沿补偿方向(行内向右)在等待最长的一行净损失从 55.3 元变到 -2.4 元,改善 57.8 元;沿等待方向(列内向下)在 1.5 倍补偿一列从 17.3 元升到 29.1 元,恶化 11.7 元。补派等待每拉长 20%,净损失就回吐 11.7 元;而补偿从 0 加到 3 倍才补回 57.8 元——平台真正该改的是派单速度,不是红包大小。

图 7 补派成功率灵敏度:班次回收与等待单数

4.7 第三维:补派成功率 图 7 让补派成功率整体缩放 0.5—1.1 倍。回收从 108.8 元升到 134.0 元,等待单数从 0 起升到 7 起。成功率是“等不等”的开关:成功率低于 0.7 时,等待的期望收益已经打不过转接,模型自动把等待关掉。

图 8 时间预算—回收前沿与加班不可行区

4.8 时间预算前沿 图 8 横轴是实际占用班次、纵轴是回收,灰区是超过 220 min 的加班区。前沿从左下向右上单调抬升,斜率就是 \(\lambda\) = 0.156 元/min。本案星标正好压在 220 min 竖线上:从 205 min 放宽到 227 min,回收从 118.9 元升到 128.8 元;曲线前陡后平,本案处的边际值就是 0.156 元/min——这就是“班次时长”在骑手手里的价格。

图 9 4000 组情景下四种方案的净损失累计分布

4.9 情景分布 图 9 用 4000 组伯努利补派实现重算四种方案。5% 分位:优化 13.9 元、全转接 51.2 元、全等待 38.5 元、全回商圈 110.5 元;均值分别为 36.4、55.3、73.0、110.5 元。优化方案整条 CDF 最靠左,说明它不是靠某一次好运赢的,而是在每一起事件上都少亏一点。

图 10 优化方案逐事件的回收构成与净损失

4.10 逐事件回收构成 图 10 拆开优化方案的每一单:橙色是取消补偿、蓝色是新单收入、绿色是等待机会成本、灰色是空驶成本,黑菱形是净回收,红三角是“原单 + 沉没”的应得。补偿那一小段橙色平均只有 2.6 元,而红三角与黑菱形之间的落差平均 3.1 元/起——落差不大,是因为补派单本身更贵;真正被吞掉的是 66.8 min 的时间,折成班次就是 220 min 里的 30%。

5 结论

  1. 沉没成本不进目标、只进账本:12 起事件共沉没 66.8 min、折 36.7 元,它不改变最优选择,但决定了这一晚净亏 36.9 元。

  2. 优化调度 36.9 元 < 全转接 55.3 元 < 全等待 73.2 元 < 全回商圈 110.5 元。全等待与全回商圈分别超时 28 min、26 min,在 220 min 班次里不可行——“死等”不是策略,是加班。

  3. 时间影子价格 \(\lambda\) = 0.156 元/min。低于这个汇率的机会,等一分钟都是亏;临界等待平均 9.5 min,平台实际补派等待 7.5 min,只有 7 起事件等得起。

  4. 5 起事件的补偿低于临界值、平均缺 1.51 元/单,补偿覆盖率仅 86%。补偿是转移支付,且被班次时长打了折(斜率 0.69):它只能分摊损失,不能消除损失;真正能降损失的是缩短补派等待、提高补派成功率。

  5. 回商圈在 12 起事件里一次都没被选中:它同时最慢和最穷,只在“商家离商圈极近且转接单极差”时才有意义——这条结论反对“白跑完就回老地方”的直觉。

参考文献

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

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