案例090 雨天的红灯

案例090 雨天的红灯

摘要:暴雨天闯红灯省 40 秒,雨天事故率升到 2.5 倍。按题面口径重算单次成本:事故 \(2.5\times10^{-4}\times18000=4.50\) 元、罚款 \(0.15\times50=7.50\) 元、扣分折算 8.00 元,合计 20.00 元(题面写 11.2 元,差 8.80 元),减去省时收益 0.16 元,净亏 19.84 元/次。以 5 个路口的 0-1 变量 \(z_l\) 建 \(\min\sum c_lz_l\)、\(\sum z_l\le0\) 的合规模型,最优值 \(Z^{*}=0\);放宽到 \(\sum z_l\le1\) 得 19.83 元,两者之差 -19.83 元/次即违规的隐含价值,为负。再以罚函数(罚价=期望罚款 7.50 元)软化合规,模型闯 4 个路口、自报赚 7.17 元、实亏 75.06 元,说明合规不能用价格替代;临界罚款 \(F^{*}_l=v_{\mathrm{sub}}s_l/(60q_l)\) 为 47.3—73.7 元。罚款调到 0,违规仍亏 12.33 元——事故期望不因没被抓而消失。

关键词:合规硬约束;违规的隐含价值;罚函数失效;期望成本;闯红灯

1 问题提出

1.1 问题是什么

暴雨天,红灯还有 40 秒。闯过去,这一单能赶上;不闯,就超时。题面把这件事算成一道加减法:事故期望 4.50 元 + 罚款 7.50 元 + 扣分折算 8.00 元 = 20.00 元,减去省下的 40 秒值 0.16 元,净亏 19.84 元——不闯。

这道题看起来太简单,简单到不值得建模。但它有两个值得做的理由。第一,题面给的数字对不上:写的是 11.2 元,三项实算是 20.00 元,差 8.80 元。如果照抄 11.2 元往下算,结论仍然是"不闯",但"违规到底多贵"会被低估 44%。一个结论正确、数字错误的模型,比没有模型更危险,因为它会被引用。第二,"不闯"这个结论在多强的约束下成立:如果允许闯一个呢?如果把"合规"从硬约束改成罚函数呢?合规一旦被标价,价格低到什么程度模型就会翻?

我们把"合规"写成硬约束 \(\sum_l z_l = 0\),再跑放宽版(允许闯 1 个、且必须省够 40 秒)和罚函数版(软约束、罚价等于期望罚款 7.50 元),三个目标值放在一起,差额就是违规的隐含价值:-19.83 元/次。按题面原数算是 \(-11.04\) 元/次,按实算口径是 -19.83 元/次——两个数都是负的,方向一致,量级差近一倍。违规不但不合规,在经济上也是负收益。

1.2 为什么要优化

三条理由。其一,数字本身要复核:题面三项指标与结果差 8.80 元,这类"结论对、过程错"的引用最容易被继承,也最难被发现。其二,"不合规"需要一个价签:只有把它折算成元/次,才能和"省 40 秒"放在同一把尺子上比,否则讨论永远停在"应该不应该"。其三,约束的形式会改变答案:同一个模型,\(\sum z_l\le 0\) 与"违规罚 50 元"给出完全不同的解——这不是参数问题,是建模问题。

1.3 Gurobi 如何求解

建模为 5 个 0-1 变量、1 条主约束的整数规划,四次求解(合规 / 只放宽 / 放宽且赶上 / 罚函数)全部根节点收敛,最长 <0.01 s。另用 \(2^{5}=32\) 个子集穷举复核,与 Gurobi 相差 0(数值零)。式 (6) 的临界罚款用解析式直接生成,与逐点求解一致。

2 数学模型

2.1 符号说明

路口 \(l=1,\dots,5\);省时 \(s_l=34\)—48 s;平均时间价值 \(v=0.24\) 元/min;赶单边际价值 \(v_{\mathrm{sub}}=13.0\) 元/min;增量事故率 \(\Delta p_l=1.5p_{0l}\)(1.50—3.60 次/万次);事故损失 \(L=18000\) 元;被拍概率 \(q_l=0.10\)—0.22;罚款 \(F=50\) 元;扣分折算 \(D=8.00\) 元;0-1 变量 \(z_l\)。

2.2 目标函数与约束条件

设路口 \(l=1,\dots,5\),闯灯省时 \(s_l\) 秒(34—48 s),平均时间价值 \(v=0.24\) 元/min;\(p_{0l}\) 为雨天基线事故率,闯灯后升至 \(2.5p_{0l}\),增量 \(\Delta p_l=1.5p_{0l}\);一次事故期望损失 \(L=18000\) 元;被拍概率 \(q_l\)(0.10—0.22),罚款 \(F=50\) 元;扣 3 分折算 \(D=8.00\) 元。\(z_l\in\{0,1\}\) 表示是否在该路口闯灯。单次闯灯的期望成本为

\[c_l=\underbrace{\Delta p_l\,L}_{\text{事故}}+\underbrace{q_l F}_{\text{罚款}}+\underbrace{D}_{\text{扣分}}-\underbrace{v\,s_l/60}_{\text{省时收益}}\tag{1} \]

基准口径(\(\Delta p=2.5\times10^{-4}\)、\(q=0.15\)、\(s=40\) s)代入:4.50 + 7.50 + 8.00 − 0.16 = 19.84 元。三项实算 20.00 元,题面写的 11.20 元复算不出来;差额 8.80 元与扣分折算 8.00 元同量级,最可能是题面把扣分项漏计(或折半)后再有 0.80 元的取整差。本文一律按实算口径,并在结果文件里同时保留两个数。

合规模型把"不许闯"写成硬约束,不是一个可以花钱赎买的罚项:

\[\min\ Z=\sum_{l=1}^{5} c_l z_l\quad \mathrm{s.t.}\ \sum_{l=1}^{5} z_l\le 0,\ \ z_l\in\{0,1\}\tag{2} \]

约束右端为 0,可行域只剩 \(z\equiv 0\),\(Z^{*}=0\)。把右端放宽到 1 得放宽版(式 3);注意式 (3) 必须带上"省够 40 秒"这一条:只把右端从 0 放宽到 1、不要求赶上,模型仍然选 \(z\equiv0\)(目标值还是 0)——因为每个 \(c_l\) 都是正数,违规连"被需要"的价值都没有。违规之所以出现在场景里,唯一原因是"不闯就赶不上"。

\[Z^{*}_{\mathrm{free}}=\min\Big\{\sum_l c_l z_l:\ \sum_l z_l\le 1,\ \sum_l s_l z_l\ge 40\Big\}=\min_{l:\,s_l\ge 40} c_l=19.83\tag{3} \]

\[\Delta Z=Z^{*}_{\mathrm{strict}}-Z^{*}_{\mathrm{free}}=0-\min_{l:\,s_l\ge 40} c_l=-19.83\ \text{元/次}\tag{4} \]

就是"允许违规一次"的隐含价值。它为负,含义是:合规约束不是"牺牲效率换安全",它直接把一个负收益的选项删掉了——删掉之后目标反而更小(这里是 0 对 19.83)。

罚函数版故意把合规写成可交易的价格:不设硬约束,把"违规"按期望罚款 7.50 元计价,按赶单的边际时间价值 \(v_{\mathrm{sub}}=13.0\) 元/min 计收益,

\[\min\ \sum_l \big(q_lF-v_{\mathrm{sub}}s_l/60\big)z_l\quad \mathrm{s.t.}\ \sum_l z_l\le 5\tag{5} \]

系数 \(q_lF-v_{\mathrm{sub}}s_l/60\) 在 4 个路口转负,模型于是选了 L1、L2、L3、L4。

2.3 规模与性质

5 个 0-1 变量、1 条约束,无连续决策。规模小到可以完全复核:32 个子集穷举与 Gurobi 差 0(数值零),说明结论全部落在系数上而不是算法上。真正的难点不在求解,而在"合规"该写成约束还是写成罚项——这一处建模选择决定了模型会不会建议闯灯。

3 Gurobi 求解实现

3.1 建模要点

五个 0-1 变量、1 条约束,Gurobi 四次求解全部在根节点收敛,最长 <0.01 s。

m.addConstr(gp.quicksum(z[i] for i in range(n)) <= kmax, name="comply")
m.addConstr(gp.quicksum(S_S[i] * z[i] for i in range(n)) >= sreq, name="catch")
m.setObjective(gp.quicksum(cost[i] * z[i] for i in range(n)), GRB.MINIMIZE)

合规版与放宽版只差两行:kmax 从 0 改成 1,再加一条"必须省够 40 秒"的覆盖约束;罚函数版换一套系数、kmax 取 5。代码没有技巧,全部工作在系数怎么来:事故项用的是"闯灯相对不闯灯的增量率"乘以"一次事故的期望损失",不是"赔个餐费";罚款项用的是"被拍概率"乘以"单次罚款",不是"闯一次罚 50";扣分项用的是"3 分折 8.00 元",不是"分不要钱"。

校验。 五个变量共 \(2^{5}=32\) 个子集,穷举与 Gurobi 的最优值相差 0(数值零)。表 1 是逐路口明细,净成本从 15.56 元(体育东路)到 25.29 元(环市东路),全为正。

表 1 五个路口的闯灯参数与单次成本(损失 1.8 万元、罚款 50 元、扣分折算 8 元)

路口 名称 省时 / s 增量事故率 / 万次 被拍概率 事故项 / 元 罚款项 / 元 净成本 / 元 临界罚款 / 元
L1 体育东路 34 1.50 0.10 2.70 5.00 15.56 73.7
L2 中山一立交 38 2.00 0.12 3.60 6.00 17.45 68.6
L3 客村立交 42 2.50 0.15 4.50 7.50 19.83 60.7
L4 珠江隧道口 46 3.00 0.18 5.40 9.00 22.22 55.4
L5 环市东路 48 3.60 0.22 6.48 11.00 25.29 47.3

表 2 三种建模方式的对照:合规能不能被价格替代

方案 约束形式 选中路口 模型目标 / 元 真实净成本 / 元 判定
合规版 \(\sum z_l\le 0\) — 0.00 0.00 不闯灯,唯一可行解
放宽版 \(\sum z_l\le 1,\ \sum s_lz_l\ge40\) L3 19.83 19.83 赶上这单,最便宜也要 19.83 元
罚函数版 \(\sum z_l\le 5\),罚价 7.5 元 L1、L2、L3、L4 -7.17 75.06 自报赚 7.17,实亏 75.06

三个数字连起来读:合规 0.00;放宽到 1 个,最优也只能挑最便宜的那个路口,仍要付 19.83 元;罚函数版自报赚 7.17 元,把漏计的事故 16.20 元、扣分 32.00 元和时间价值高估 34.03 元补回来,实际亏 75.06 元,误差 82.23 元。

3.2 求解结果

合规版 \(z\equiv 0\)、\(Z^{*}=0.00\) 元;放宽版 \(z=[0 0 1 0 0]\)、\(Z^{*}=19.83\) 元;罚函数版 \(z=[1 1 1 1 0]\)、目标 -7.17 元、真实 75.06 元;只放宽不要求赶上则 \(Z^{*}=0.00\)。四次求解最长 <0.01 s。

4 结果分析

4.1 结构:三项成本谁说了算

图 1 单次闯灯成本的三项拆解(事故 4.50、罚款 7.50、扣分 8.00)与合计,虚线为题面给的 11.20 元

图 1 把式 (1) 的三个正项和一项负项画成五根棒。事故 4.50 元、罚款 7.50 元、扣分 8.00 元,三根都不短;合起来 20.00 元,是题面 11.20 元的 1.79 倍。最右边那根绿棒(省时收益 0.16 元)短到几乎看不见——它只有合计成本的 0.8%。这张图是整个案例的体检报告:不是某一项特别贵,而是"省 40 秒"这件事本身太便宜,任何一项成本单独拿出来都压得住它。扣分项 8 元是三项里最大的一项,恰恰是题面最容易被漏掉的一项。

图 2 五个路口的省时—净成本散点(气泡大小为被拍概率),省的几十秒只值一两毛钱

图 2 换个切法:横轴省时、纵轴净成本,气泡大小是被拍概率。五个点全在零线之上 15 元以上,而且排布有规律——省时越多的路口(环市东路 48 秒)净成本越高,因为省时收益涨得慢(每秒 0.004 元)、而事故与罚款涨得快。等收益线(0.24 元/min 的斜率)贴着地面,五个点离它有 10—25 元的高度差。"我很急"这个理由要成立,需要时间价值涨到 28.6 元/min 以上,是本案的 119 倍。

4.2 决策:合规是硬约束,不是可以买断的罚项

图 3 三种建模方式的净成本:合规硬约束 0.00、放宽到 1 个 19.83、罚函数软约束自报 -7.17(真实 75.06)

图 3 是全篇的核心。合规版(\(\sum z_l\le 0\))目标 0.00 元,可行域只有一个点;放宽版(\(\le 1\)、须省够 40 秒)目标 19.83 元——五个路口里省时够 40 秒的只有 L3、L4、L5,模型挑了最便宜的客村立交,但仍然是亏 19.83 元;罚函数版把合规换成"罚价 = 期望罚款 7.50 元"的软约束,模型一口气闯了 4 个路口,自报赚 7.17 元——而它的真实成本是 75.06 元,漏计 82.23 元。三个数字的顺序说明:合规约束不是负担,它把一个负收益选项直接删掉了;罚函数版不是"放宽",是把一个不可定价的东西硬塞进了价格体系,一旦塞进去,模型就会顺着价格往下滑。

图 4 一趟五个路口的累积净成本(左轴)与累积省时(右轴):省 208 秒、净赔 100.35 元

图 4 把一趟五个路口摊开。五个都闯:累积成本一路爬到 100.35 元,右轴累积省时 208 秒;罚函数版闯四个:爬到 75.06 元;合规不闯:成本恒为 0。左轴和右轴的量级差了两个数量级——省 3.5 分钟,赔几十块钱。这就是"雨天红灯"这道题的全部结构:时间在这里不值钱,风险和罚款在这里很值钱。

4.3 主灵敏度:把罚款调到零,违规仍然亏

图 5 罚款额从 0 涨到 300 元时的单次净成本(左轴)与违规的隐含价值(右轴)

图 5 的横轴是罚款额,从 0 调到 300 元。左轴是两条净成本曲线(客村立交、体育东路),右轴是违规的隐含价值(式 4 的 \(\Delta Z\))。三条读法:其一,罚款涨到 300 元,客村立交的净成本从 12.33 元涨到 57.33 元,一路单调上升,最优解始终是"不闯"——罚多少都不改变决策,只改变违规有多贵。其二,右轴的隐含价值在罚款为 0 时已经是 -12.33 元,罚款从 0 涨到 50 元只让它再负 7.5 元,占比不到四成。其三,也是最要紧的一条:把罚款调到 0,客村立交的净成本仍有 12.33 元(事故 4.50 + 扣分 8.00 − 省时 0.17)。事故的期望值不会因为"没被抓"而消失,这是所有"罚得轻所以可以闯"的论证共同的漏洞。

图 6 罚款额 × 扣分折算 的单次净成本地形,全图无负值区

图 6 把罚款额与扣分折算摊成平面,颜色是单次净成本。整张图没有一个负值区:最浅的色块(罚款 0、扣分不折价)也有 4.33 元。这意味着在 (1) 式的口径下,任何参数组合都不会让闯灯变成正收益——除非把事故损失调到接近 0(那就等于宣布"撞了也不会有事"),或者把时间价值调到 10 元以上(那就是图 2 的等收益线)。星标 (50, 8) 落在"10—25 元"档的中部,离最近的可能翻正区域隔着整个色阶。

4.4 第三维与前沿:罚价失效的临界线在哪

图 7 第三维:挡住各路口所需罚款随赶单边际时间价值的变化,阴影为现行 50 元罚价的失效区

图 7 回答"罚函数为什么会失效"。把式 (5) 的系数令零,得到挡住第 \(l\) 个路口所需的罚款额

\[F^{*}_{l}=\frac{v_{\mathrm{sub}}\,s_l}{60\,q_l}\tag{6} \]

横轴是赶单的边际时间价值(超时扣 20 元、差 92 秒,合 13.0 元/min),纵轴是临界罚款。五条线从左下往右上走:越急,需要的罚款越高。本案罚价 50 元是一条水平虚线:13.0 元/min 对应的客村立交临界罚款是 60.7 元,已经高于 50 元,挡不住;只有当赶单价值降到 10.7 元/min 以下,50 元才重新有效。反过来,最容易被挡住的是环市东路(临界只要 47.3 元,50 元已够),最难挡的是体育东路(要 73.7 元)。这就是"罚函数定价过低"的准确含义:它把合规标了一个固定价格,而违规的收益随紧迫度浮动,价格一旦被浮动收益超过,约束就名存实亡。

图 8 省时—成本的组合前沿,红色阴影是合规约束下整片不可行的区域

图 8 是五个路口全部 32 种组合的省时—成本平面。灰点是"闯任意组合"的方案,蓝线是成本—省时前沿(给定省时下的最小成本),红色斜纹阴影是整个"省时 > 0"的区域——在合规约束 \(\sum z_l\le 0\) 下,它全部不可行。这是本案例最直白的一张图:合规不是把可行域"约束小一点",而是把它压成一个点。前沿本身也在零线之上:想多省一秒,成本就往上走,前沿永远不会跌到 0 以下。

4.5 分布与拆解:均值之外没有安慰

图 9 事故期望成本的 20000 次抽样分布与累计概率,左侧竖线是省时收益

图 9 处理一个常被忽略的问题:4.50 元是均值,不是每一次的实付。用对数正态描述增量事故率(中位 \(2.5\times10^{-4}\))与事故损失(中位 1.8 万元),20000 次抽样的乘积分布如上:中位数 4.46 元,长尾拖到 30 元以上。左侧那条几乎贴着纵轴的绿线是省时收益 0.17 元——事故项高于省时收益的样本占 100.0%。换句话说,"闯一次省 40 秒"这件事,在任何一个可能的参数实现下都不划算,不是"平均不划算"。

图 10 五个路口的三项成本堆叠(最右为五口合计),绿色菱形为省时收益的负向标注

图 10 把三项成本按路口堆叠。五个路口合计 22.7 元事故、38.5 元罚款、40.0 元扣分,省时收益合计只有 0.83 元(绿色菱形贴在零线上)。扣分项在每个路口都是最厚的一块(8.00 元),占单次成本的 40%;罚款项随被拍概率从 5 元涨到 11 元,是唯一随路口差异化的可政策变量。
再看一年:1080 次"赶时间遇红灯"的机会,每次都闯客村立交,一年亏 21419 元、期望摊上 0.27 次事故。21419 元不是一个大数字,它之所以小,恰恰是因为每次只亏 19.84 元——但事故不是按期望赔付的,它是一次性付清的。

5 结论

(1)题面的数要复核:三项实算 4.50 + 7.50 + 8.00 = 20.00 元,题面写 11.20 元,差 8.80 元(低估 44%)。差额与扣分折算 8.00 元同量级,最可能是漏计扣分项。结论(不闯)不变,但"违规有多贵"被低估了近一半。本文一律按实算口径,两个数都留在 results_090.json 里。
(2)合规版最优值为 0,放宽版为 19.83 元,隐含价值 -19.83 元/次:五个路口的净成本全为正(15.56—25.29 元),合规约束删掉的是一个负收益选项,而不是牺牲效率换取安全。
(3)合规是硬约束,不能被价格替代:罚函数版把合规标价成期望罚款 7.50 元,按赶单边际价值 13.0 元/min 计收益,模型闯了 4 个路口、自报赚 7.17 元,实际亏 75.06 元(漏计 82.23 元)。挡住各路口所需罚款 \(F^{*}_l=v_{\mathrm{sub}}s_l/(60q_l)\) 在 47.3—73.7 元之间,现行 50 元已经在失效区。
(4)罚款调到 0,违规仍亏 12.33 元:事故 4.50 + 扣分 8.00 − 省时 0.17。二维平面上(图 6)不存在负成本区,违规的代价主体从来不是罚款,而是事故的期望值——它不因"没被抓"而消失。
(5)结论是不闯灯:这是模型与硬约束双重否定的选项,也是唯一可行解。合规不是"成本项",是可行域的定义;把它写成可以花钱赎买的罚项,模型立刻会替你算出"闯几个最划算"——这个结果本身就是对"用价格替代合规"这种做法的否定。


参考文献

[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_090.py;数据与结果见同目录 .csv / .json,图见 figs/

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