案例086 超时罚款最小化
案例086 超时罚款最小化
摘要:8 单、一条车、两档阶梯罚款:超时 5 min 罚 3.5 元,超 30 min 再加 3.5 元。用顺序变量 \(y_{ij}\) 与完成时刻 \(C_i\) 建 VRPTW,两档罚款用 \(u_i,v_i\) 两个 0-1 变量叠加线性化,目标 \(\min 3.5\sum u_i+3.5\sum v_i\)。Gurobi 求得最优顺序 O1 → O7 → O4 → O5 → O6 → O3 → O8 → O2,罚款 14.0 元(一档 3 单、二档 1 单)、里程 34.00 km。反面实验删去 \(v_i\le u_i\),模型给出 10.5 元的假解(低报 25%),解中出现"\(u_i=0,v_i=1\)"的荒谬组合。大 \(M\) 的理论保守界由最长 8 段行程推出为 139,实测最小正确值 25;\(M\) 增至 60 时分支节点由 4963 增到 16398。灵敏度显示:阈值压到 2 min 罚款 17.5 元、放到 5—15 min 恒为 14.0 元,加倍费率 0.5→1.5 倍罚款由 12.2 升到 15.8 元;只求里程最短的解与最优解同为 34.00 km,罚款却高 42.0 元。
关键词:两档罚款;阶梯函数线性化;VRPTW;大 M;逻辑约束;帕累托前沿
1 问题提出
8 单在一条城区路网上先后配送,单点服务 4 min,车从站点出发、只在 0 时刻发一次。每单有一句承诺:O1 在 30 min、O2 在 34 min……O8 在 54 min 前送到。承诺不是越早越好,而是阶梯定价:超时 5 min 以内不罚,超过 5 min 罚 3.5 元,超过 30 min 再加罚 3.5 元、合计 7.0 元。运力只有一台车、一条路,8 单必须全部送完,唯一能做的是排顺序——但顺序同时决定里程和罚款,两者并不一致。
这个案例的难点不在规模,而在分段函数的线性化。罚款是超时分钟数的阶梯函数 \(f(\ell)\):\(\ell\le 5\) 为 0,\(5<\ell\le 30\) 为 3.5,\(\ell>30\) 为 7.0。阶梯不是凸函数,不能用一个连续变量加斜率表示,必须用两个 0-1 变量叠加。叠加之后两档之间多了一条隐含的上下级关系 \(v_i\le u_i\)——漏掉它,模型会理直气壮地给出"严重超时但没超时"的答案。本题要求把这个反面实验也跑一遍,给出假解虚低的罚款数字。
2 数学模型
设客户集合 \(\mathcal{N}=\{1,\dots,8\}\),\(0\) 为站点;\(t_{ij}\) 为 \(i\) 到 \(j\) 的行程时间(min),\(s=4\) 为单点服务时间,\(D_i\) 为承诺时刻。决策变量为顺序变量 \(y_{ij}\in\{0,1\}\)(\(i\) 紧接在 \(j\) 之前,\(i,j\in\{0\}\cup\mathcal{N}\))、完成时刻 \(C_i\ge 0\),以及两档超时指示 \(u_i,v_i\in\{0,1\}\)。
顺序与时间递推。 每单恰有一个前驱、至多一个后继:
其中 \(i=0\) 时 \(C_0=0\)。式 (2) 只给下界,沿任意一条被选中的弧时间严格递增,因此不会出现子回路,不需要额外的子回路消除约束。
两档罚款。 令 \(\ell_i=C_i-D_i\),两档门控为
目标是最小化罚款总额:
式 (4) 的系数之和正好构成阶梯:只超一档付 3.5,两档都超付 7。式 (3) 最后一条不能省:只保留前两条时,令 \(u_i=0,v_i=1\) 既能放开 30 min 那条线、又只付 3.5 元,模型会主动选择这种"严重超时却没超时"的组合。
3 Gurobi 求解实现
模型用 Gurobi 直接求解:8 单共 64 个 \(y\) 变量、8 个 \(C\)、16 个 0-1 变量。目标在式 (4) 后加一项 \(0.001\times\) 里程做字典序近似——量级最多 0.03 元,远小于 3.5 元的档差,改不动罚款,只在罚款相同的方案里挑一条最省油的路(否则等罚路径有无穷多条,报告里的顺序不可复现)。
大 M 的取值。 任何一条路径的完成时刻不超过"最长的 8 段行程 + 8 次服务",即
于是式 (3) 中 \(M\ge\max(0,\bar C-\min_i D_i-5)=139\) 是保守上界。上界按“最坏路径”估,而最优解最长只超 49 min,门控只需盖住 \(49-30=19\);按 \(M=15,25,60\) 逐点试解,实测最小正确值 \(M=25\),比保守界小一个量级。表 1 给出 \(M\) 的影响:
表 1 大 M 对罚款、分支节点数与求解时间的影响
| M | 罚款 / 元 | 分支节点 | 耗时 / s |
|---|---|---|---|
| 15 | 21.0 | 4963 | 1.29 |
| 25 | 14.0 | 12524 | 2.58 |
| 60 | 14.0 | 16398 | 4.00 |
两头都有代价:\(M=15\) 时连 49 min 的超时都表示不出来(二档右端只有 \(30+15=45\)),最优罚款被抬到 21.0 元;\(M\) 从 25 抬到 60,可行域变松、分支节点从 12524 涨到 16398,4 s 上限内已搜不完。取值原则是"够用即可":按实际最大超时定,而不是随手写 \(10^6\)。
4 结果分析
4.1 结构:承诺与完成差在哪

最优顺序下各单承诺时刻与完成时刻(杆长为超时分钟数)
图 1 是按最优顺序排开的 8 根棒棒糖:方块是承诺 \(D_i\),圆点是完成 \(C_i\),杆长就是超时分钟数。最优顺序为 O1 → O7 → O4 → O5 → O6 → O3 → O8 → O2,里程 34.00 km,罚款 \(Z^*=14.0\) 元,其中一档 3 单、二档 1 单。注意 O2 排在最后、超时 49 min——它离站点最远且承诺不晚,放在末尾是"少罚"与"少跑"折中的结果,不是随手排的。

超时分钟—罚款额散点(气泡大小为完成时刻,虚线为 5/30 min 两档线)
图 2 把每单放进罚款阶梯:横轴是超时分钟,纵轴是该单罚款。点在 \(\ell\le 5\) 区间的单价为 0,落在 5—30 之间跳成 3.5,越过 30 再跳 3.5。阶梯的跳变位置决定了优化的"靶心":把一单从 5.5 min 压到 4.5 min 能省 3.5 元,而从 12 min 压到 11 min 一分不省——这就是为什么最优解里会出现"差一点就超时"的临界单。

三种解法对比:漏 v≤u 的假解 / 正确解 / 只求里程最短
图 3 是本案的教学核心。漏写 \(v_i\le u_i\) 后模型给出 10.5 元,比正确值 14.0 元虚低 3.5 元(低报 25%)。假解里 O2 超时 49 min,却记成 \(u_i=0\)、\(v_i=1\),只交一份钱。原因很直接:把 30 min 那条线的门控变量直接置 1、而 \(u_i\) 仍为 0,等于"承认严重超时、却否认超过 5 min",只付一档的钱。第三根柱是只看里程、不看罚款的解:里程 34.00 km 与最优解完全相同,罚款却高达 56.0 元,多付 42.0 元。里程对罚款几乎没有解释力——同样的 34 km 上,顺序不同、罚款能差 4.0 倍。把里程当罚款的代理指标,是这类问题最常见的偷懒。
4.2 时序与灵敏度

8 单完成时刻轨迹与各自承诺线(阴影为超时区间)
图 4 把顺序摊平成时间轴:蓝线是累计完成时刻,灰虚线是各单的承诺。两条线在 O1 处贴合,越往后张口越大——超时集中在路径末段,因为前段每一分钟都会被后段继承。这也解释了为什么"把承诺最紧的单往前挪"未必有效:挪动会同时改变后面所有单的完成时刻,收益是非线性的。

一档阈值 2—15 min 对罚款总额(左轴)与计罚单数(右轴)的影响
图 5 把阈值两端都试了:压到 2 min,罚款跳到 17.5 元(多罚一单);放到 5 min 落回 14.0 元;再放宽到 10、15 min 仍是 14.0、14.0 元,一分不降。原因在图 2:计罚单的超时是 23.5、17.5、49.0 min,全部落在 15 min 之外。台阶是离散的——阈值必须越过某个真实超时值才省钱,停在两档之间等于白放宽;这也是"宽限 5 min"这类条款必须对着实际超时分布定的原因。

一档阈值 × 接单量 的罚款总额热图(星号为本案参数)
图 6 加上第二个维度:接单量从 4 涨到 8(按承诺时刻取前 \(n\) 单)。同一阈值下,单量每加一单罚款跳一档;同一单量下,阈值放宽罚款下降。左上角(4 单、15 min)几乎免罚,右下角(8 单、5 min)最贵,本案的星号正落在右下。这张图回答的是运营问题:多接两单带来的罚款增量(约 10.5 元)远小于两单的配送收入,罚款不该成为限单的理由,但它是定价的底线。

加倍费率系数 0.5—1.5 对罚款总额的影响(两条阈值曲线)
图 7 把"加倍"的力度做成参数 \(k\)(二档罚 \(3.5k\))。\(k\) 从 0.5 涨到 1.5,罚款从 12.2 涨到 15.8 元,增量全部来自那 1 个严重超时单。两条曲线在 \(k=0.5\) 处差 1.8 元、在 \(k=1.5\) 处汇合:阈值 5 min 时那一单必然吃二档,阈值放到 15 min 后它退回一档,费率再高也只按一档收。阈值决定"有几单进二档",费率决定"每单罚多少"——前者是运营口径、后者是合同条款,改口径比改费率省得多。
4.3 前沿、分布与贡献

里程预算—最小罚款的前沿(阴影为里程不可行的预算区间)
图 8 换一个问法:给定里程预算 \(\bar L\),求该预算下的最小罚款。预算压到 33 km 直接无可行路线(阴影),到 34 km 罚款就压到 14.0 元,再放宽到 50 km 一分不降。前沿是水平的——里程不是可以换罚款的资源,8 单的总行程已经决定了最后一单必然超时,多跑几公里也换不回一单准时。真正能动的是承诺时刻与运力,而不是路径长度。

超时分钟分布(柱)与累计分布(线)
图 9 看分布形状:5 单超时,其中 3 单越过 5 min 宽限、真正计罚,另外 2 单在宽限内;超时中位数 2.5 min、最长 49.0 min。分布是双峰的——一簇贴着 5 min 线(临界单,压一压就免罚),一簇在 30 min 以上(结构性超时,压不动)。前者是排程能救的,后者只能改承诺或加运力。

各单罚款贡献分解:一档 3.5 元与加倍再加 3.5 元
图 10 按单拆罚款:3 单各贡献 3.5 元,其中 1 单再叠 3.5 元,总额 14.0 元。贡献高度集中:1 个二档单吃掉了 50% 的罚款,而它们只占单量的 12%。这提示改进方向不是"平均提速",而是专门处理那几个 30 min 以上的单——换承诺、换顺序或拆单。
4.4 为什么 14 元是下限
把总行程与最晚承诺放在一起看:8 单跑完要 83 min,而 8 个承诺里最晚的只有 54 min,最后一单无论怎么排都不可能早于 83 min 完成,至少有一单必然越过 30 min 的二档线,7 元是结构性下限。余下 7 元来自另外 3 单的一档罚款,只能在 14.0 与 17.5 元之间挪动。若要把罚款压到 7 元以下,唯一的办法是改承诺或加一台车,而不是继续调顺序。
5 结论
(1)最优顺序 O1 → O7 → O4 → O5 → O6 → O3 → O8 → O2,罚款 14.0 元(一档 3 单、二档 1 单),里程 34.00 km,全部 8 单在 83 min 内送完。
(2)两档阶梯必须用两个 0-1 变量叠加,且 \(v_i\le u_i\) 不可省。漏掉后模型给出 10.5 元的假解,比真值低 3.5 元(25%),表现为"\(u_i=0,v_i=1\)"——严重超时却没超时。
(3)大 M 按实际最大超时定:结构上界 139(按最坏路径估)太松,实测最小正确值 25;\(M\) 从 25 抬到 60,分支节点从 12524 涨到 16398、求解变慢;\(M=15\) 则把最优解切掉、罚款虚高到 21.0 元。
(4)灵敏度:一档阈值 5→15 min,罚款 17.5→14.0 元,台阶式递减;加倍费率系数 0.5→1.5,罚款 12.2→15.8 元,近似线性。阈值是运营口径,费率是合同条款。
(5)里程最短 ≠ 罚款最少:最短路线 34.00 km 只省 0.00 km,罚款却多 42.0 元。罚款是分段常数、里程是连续量,两者不同价,必须一起进目标或做成帕累托前沿。
参考文献
[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_086.py;数据与结果见同目录 .csv / .json,图见 figs/

浙公网安备 33010602011771号