案例 045 一单崩,全崩:级联风险与冗余/隔离设计
案例 045 一单崩,全崩:级联风险与冗余/隔离设计
摘要:8 单串成一趟,最优点序把最大延误压到 0.7 min,代价是整条链的余量几乎为零。一旦某一单出事——商家取消、客户失联、或干脆晚了 12 min——延误沿链向后传递,后面每一单都跟着崩。本文用 Gurobi 先解 \(\min L^{\max}\) 的极小极大排序,再把"单点故障"写成沿链传播的延误算子,对串联全损、分批隔离、预留冗余三种方案分别算最坏情景损失与期望损失。结果:串联方案最坏一次性损失 123.5 元,是单均损失的 8.0 倍;4 批隔离把期望损失从 68.8 元降到 23.4 元(降 66%),只多跑 6.9 km;冗余 12 min/单 把最坏损失压到 17.0 元(1 单),但运行成本升到 41.8 元。若服务底线是"最坏损失不超过 40 元",只有冗余方案可行;若只看期望总成本,隔离最划算——这正是 \(\varepsilon\)-约束要表达的取舍。
关键词:级联失效;极小极大延误;分批隔离;冗余时间;期望损失;\(\varepsilon\)-约束
1 问题提出
1.1 问题是什么
午高峰一趟 8 单,出餐口只有一条通道。第 1 单商家临时取消,骑手在店里解释、等退款、再联系客户,前后耗掉 12 min;等他冲出去,后面 7 单的承诺时刻已经全部失效。这不是"某一单晚了",而是一条串联链被一个节点拖垮。
题目给的是极小极大结构:让最惨的那一单尽量不惨。但真正要回答的是商业问题——要不要为小概率的单点故障付出常态成本。
1.2 为什么要优化
第一,串联系统的损失是阶跃式的。8 单的余量都在 0 到 3 min 之间,任何超过 4 min 的扰动都不是"晚一点",而是整条链同时击穿。
第二,三种防崩手段的成本结构完全不同:隔离付的是里程(回驻点重新出发),冗余付的是时间(早到等待),串联什么都不付,但它把风险全部留给了最坏情景。
第三,只有一个口径会骗人。只看期望,串联每趟平均亏 68.8 元,似乎还能忍;只看最坏,一次 123.5 元,一天几趟就吃掉全天利润。两个口径必须同时摆出来。
1.3 Gurobi 如何求解
两层结构。第一层是排序:二进制 \(x_{ij}\) 选弧、连续变量 \(C_i\) 记到达时刻、标量 \(L^{\max}\) 记最大延误,目标是最小化 \(L^{\max}\),时间沿弧递推自然消除子回路。第二层是情景评估:固定最优序,枚举"哪一单出事"(8 个位置),按各方案的传播规则算损失,取最大值与等权期望。第二层是纯代数,不需要再解 MIP,所以整个案例的求解墙钟不到 2 s。
2 数学模型
2.1 符号说明
\(i,j\) 为节点(0 为驻点,\(N+1\) 为回程虚拟终点),\(D_{i}\) 为承诺时刻,\(C_{i}\) 为到达时刻,\(d_{ij}\) 为弧长,\(\tau_{ij}=3\,d_{ij}\) 为骑行时间(3 min/km),\(s_{i}=2\) min 为停靠交付,\(s\) 为故障延误,\(b\) 为每单冗余,\(g\) 为客户容忍,\(\ell_{i}\) 为单均损失,\(z_{jk}\) 为击穿指示,\(L^{\max}\) 为最大延误。
2.2 目标函数
第一层是极小极大延误,用"里程"做微小的次序打破(避免多解):
其中 \(\rho_{d}=1.2\) 元/km,\(d_{ij}\) 为弧长。系数 1000 保证 \(L^{\max}\) 绝对优先,里程只在 \(L^{\max}\) 相同的解之间起区分作用。
第二层对每个故障位置 \(k\) 算损失,再取两个口径:
\(\mathcal{B}(k)\) 是"被 \(k\) 拖下水"的订单集合,\(\ell_{j}=r_{j}+c_{p}\) 为单均损失(收入 \(r_j\) 加赔付 \(c_{p}=8\) 元),\(z_{jk}\in\{0,1\}\) 是击穿指示。
2.3 约束条件
到达时刻沿弧递推,\(M\) 取 500 保证大 M 有效:
极小极大把每单的延误压到同一个上界之下:
级联是本案的核心。故障造成 \(s\) 分钟延误,每经过一个停靠点被冗余 \(b\) 吸收一部分,剩余延误单调不增:
剩余延误超过"余量加客户容忍"就击穿,\(g=3\) min:
分批隔离改的是 \(\mathcal{B}(k)\) 的范围而不是延误本身:把序列切成 \(m\) 段,每段独立回驻点,故障只污染本段。运行成本的差别全部来自回程:
\(\omega=0.30\) 元/min 为冗余时间的机会成本。
2.4 规模与性质
9 个节点、72 条候选弧、9 个时间变量、1 个连续目标变量,第一层是标准的不对称 TSP 加极小极大时间约束。由于 \(C\) 沿弧严格递增,\(x\) 的任何子回路都会与式 (3) 矛盾,不需要额外子回路约束。第二层是 \(O(N^{2})\) 的枚举,8 单只有 8 个故障位置,直接用 numpy 扫完。
3 Gurobi 求解实现
3.1 建模要点
极小极大天然线性,这是它比 \(\sum\) 型目标更稳的原因:不需要绝对值、不需要分段,只要一个标量 \(L^{\max}\) 和 \(N\) 条线性不等式。
L = m.addVar(lb=-GRB.INFINITY, name="L")
for c in range(1, N + 1):
m.addConstr(L >= t[c] - DUE[c - 1])
m.setObjective(1000.0 * L + km, GRB.MINIMIZE)
第二个要点是别把级联写成线性。式 (5) 的 \(\max\{0,\cdot\}\) 如果改写成"延误恒定",冗余的作用会被抹平——每多一分钟冗余都应该少拖垮一单,这个"逐步吸收"必须逐跳算。
3.2 求解结果
表 1 最优序的逐单到达与余量(时刻以出发为 0,单位 min)
| 顺序 | 订单 | 送达点 | 距店 km | 承诺 | 到达 | 余量 | 单均损失 / 元 |
|---|---|---|---|---|---|---|---|
| 1 | 08 | 岗顶 | 1.0 | 10 | 3.0 | +7.0 | 15.0 |
| 2 | 01 | 天河城 | 0.7 | 7 | 6.9 | +0.1 | 16.0 |
| 3 | 02 | 珠江新城 | 1.3 | 14 | 11.2 | +2.8 | 15.5 |
| 4 | 03 | 猎德大道 | 2.0 | 18 | 16.2 | +1.8 | 17.0 |
| 5 | 04 | 冼村路 | 0.9 | 23 | 22.0 | +1.0 | 14.5 |
| 6 | 05 | 员村二横 | 2.4 | 30 | 28.9 | +1.1 | 16.5 |
| 7 | 06 | 车陂南 | 2.9 | 35 | 34.8 | +0.2 | 15.0 |
| 8 | 07 | 棠下村口 | 1.6 | 41 | 41.7 | -0.7 | 14.0 |
表 2 三种防崩方案的两个口径(单位:元)
| 方案 | 运行成本 | 最坏损失 | 期望损失 | 最坏合计 | 期望合计 | 波及单数 |
|---|---|---|---|---|---|---|
| A 串联(不设防) | 13.0 | 123.5 | 68.8 | 136.5 | 81.7 | 8 |
| B 分批隔离(4 批) | 21.3 | 32.5 | 23.4 | 53.8 | 44.6 | 2 |
| C 预留冗余(12 min/单) | 41.8 | 17.0 | 15.4 | 58.8 | 57.2 | 1 |
最优点序 08 → 01 → 02 → 03 → 04 → 05 → 06 → 07,最大延误 0.7 min,总里程 10.82 km。注意表 1 的余量列:8 单里有 7 单的余量不足 3 min,最后一单(07 棠下村口)甚至已经晚了 0.7 min。这条链没有任何吸收扰动的能力。
4 结果分析

图 1 最优点序的时序甘特(斜纹为剩余余量)
4.1 时序结构 图 1 是 08 → 01 → 02 → 03 → 04 → 05 → 06 → 07 的甘特。蓝色骑行段和绿色停靠段几乎首尾相接,斜纹的"剩余余量"薄得像纸——只有第一单(岗顶,离店 1 km)还有 7 min 的缓冲,其余全在 3 min 以内。这就是"串联"的物理含义:链条的强度等于最弱的一环,而这里每一环都很弱。

图 2 距离—到达时刻散点(气泡为单均损失)
4.2 数据全景 图 2 把 8 单摆在"距离—到达时刻"平面上,气泡大小是单均损失。余量最薄的三单(07、06、01)都在 1.0 到 1.6 km 的中近距离,而最远的 05(2.4 km)反而还有 1 min 余量;07 的余量为负,正是 \(L^{\max}=0.7\) 的来源。余量与距离不成正比,只与排位和承诺时刻有关——所以"挑近单"解决不了级联问题。

图 3 三种防崩方案的运行成本与损失对比
4.3 三方案对比 图 3 把运行成本与最坏损失并排放。串联的成本几乎为零(13.0 元),但最坏一次赔 123.5 元;4 批隔离多花 8 元里程,最坏损失砍到 32.5 元;冗余方案运行成本 41.8 元,最坏损失只剩 17.0 元。绿色菱形是"运行成本 + 期望损失",三个点分别是 82、45、57 元——期望口径下隔离最优,最坏口径下冗余最优,两个口径给出两个答案。

图 4 单点故障后延误沿链传播
4.4 级联过程 图 4 是延误沿链的传播。红线是"第 1 单崩后"的到达时刻,从第 2 单起整体抬升 12 min,全程压在承诺线之上,粉色区域就是被击穿的部分。分批隔离不在图上,因为它改的是"谁陪葬"而不是"延误多久":4 批方案的总时长被拉长到 60 min 以上,多出来的时间就是回驻点的代价。虚线是常态时序,它贴着承诺线走——余量本来就只够"不出事"。

图 5 故障强度灵敏度与波及单数
4.5 主灵敏度:故障强度 图 5 让延误从 0 扫到 24 min。串联方案在 \(s\approx 4\) min 就触顶(123.5 元,8 单全崩),此后加多少都一样——它没有阈值,只有一次性崩塌。冗余 12 min 把阈值推到 15 min 左右,曲线在 15 min 之后才抬头。隔离方案的曲线是台阶:每跨过一段余量就多崩一单,但永远只崩本批。

图 6 冗余时间 × 故障强度的最坏损失热图
4.6 二维灵敏度 图 6 把冗余 \(b\) 与故障强度 \(s\) 铺成 5×4 网格。左上角(\(b\) 小、\(s\) 大)是最坏损失 124 元的深红区,右下角(\(b=12\)、\(s\) 小)是 17 元的浅色区。等高线在 \(b\) 方向几乎垂直、在 \(s\) 方向倾斜,说明冗余对损失的边际作用在 \(b\approx 9\) min 之后就饱和:再加时间也压不动那"第一单必损"的 17.0 元底噪。

图 7 分批数的损失—里程权衡
4.7 第三维:分批数 图 7 把批数从 1 拉到 4。期望损失从 68.8 元单调降到 23.4 元,最坏损失从 123.5 元降到 32.5 元,但额外里程从 0 涨到 6.9 km,边际收益明显递减:第 2 批砍掉一半损失,第 4 批只再砍 6 元。隔离的性价比在 \(m=2\) 到 \(m=3\) 之间最高,这与"每批 3 到 4 单"的行业经验一致。

图 8 冗余扫描的前沿与不可接受区
4.8 前沿与不可行区 图 8 是冗余扫描的(运行成本,最坏损失)前沿。曲线从左上(0 冗余、124 元)陡降到右下(12 min、17 元),拐点在 \(b\approx 6\) min:此前每加 5 元成本能换回 40 元损失,此后每加 5 元只换 15 元。阴影是"最坏损失超过 40 元"的不可行区,串联方案整个落在里面。

图 9 故障位置损失分布与累计分布
4.9 损失分布 图 9 是 8 个故障位置的损失分布。串联(红)从 17 元一路排到 123 元,累计曲线几乎是一条斜线——故障位置越靠前,损失越大,且没有上限。冗余方案(蓝)的分布被压成一根 17 元的柱子,累计曲线在 0.13 处直接跳到 1.0:无论哪一单出事,损失都是一单。这就是冗余的本质——把"位置相关"的损失变成"位置无关"的常数。

图 10 逐位置对期望损失的边际贡献
4.10 逐位置贡献 图 10 把每个位置的期望贡献(\(\Lambda_{k}/N\))按方案拆开。串联的贡献从首单的 15.4 元线性衰减到末单的 1.5 元,说明风险集中在链条前段:越早出事,后面陪葬的越多。隔离把这条斜线压成锯齿(每批第一单贵、第二单便宜),冗余把它压成一条 1.9 元的平线。治理级联,本质上就是把这条斜线拉平。
5 结论
-
极小极大排序给出 0.7 min 的最大延误与 10.82 km 的最短里程,但 8 单中 7 单余量不足 3 min,这条链在结构上没有抗扰动能力。
-
一次 12 min 的单点故障在串联结构下造成 123.5 元损失,等于 8 单全损,是单均损失的 8.0 倍——级联的放大倍数等于链长。
-
分批隔离把期望损失从 68.8 元降到 23.4 元(降 66%),代价是 6.9 km 额外里程与约 8 元运行成本,是期望口径下的最优解。
-
预留冗余 12 min/单 把最坏损失压到 17.0 元、把崩溃阈值从 4 min 推到 15 min,但运行成本 41.8 元,期望总成本 57 元反而最高——冗余买的是尾部,不是均值。
-
两个口径不能互相替代。若公司把"最坏损失不超过 40 元"写成服务底线(即 \(\varepsilon\)-约束),4 批隔离(32.5 元)就已越界,只有冗余方案可行,代价是每天多付 21 元常态成本。
参考文献
[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_045.py;数据与结果见同目录 .csv / .json,图见 figs/

浙公网安备 33010602011771号