案例 064 雨天续航打八折

案例 064 雨天续航打八折

摘要:暴雨把满电续航从 \(48.0\) km 压到 \(38.4\) km,同一场雨又把单量从 \(30\) 单抬到 \(39\) 单,两头一起挤。本文把"续航随决策变化"的背包写成一条右端含整变量的约束 \(\sum_i d_i x_i \le 38.4 + 35.0 n\),在 \(39\) 个 0-1 变量加 1 个换电整变量的模型上,比较按晴天上限排程(雨天硬撑)、按雨天续航保守排程、动态降档(换电补程)三种做法。结论很硬:晴天排程把 \(45.7\) km 塞进 \(48.0\) km 的电池,只剩 \(2.3\) km 余量,续航折扣只要低于 \(0.951\) 就会崩;暴雨下它要推车 \(7.3\) km、耗时 \(109.0\) min,全天 \(483.8\) min 远超 \(430.0\) min 上限。保守排程只能送 \(28\) 单;动态降档换电 \(1\) 次、多花 \(6.0\) min,送到 \(35\) 单,比保守多 \(7\) 单,代价是 \(3.0\) 元。

关键词:容量随决策变化;续航折扣;换电补程;两维背包;推车风险

1 问题提出

1.1 问题是什么

雨天的两个变化同向恶化:电池可用里程打八折,\(E = 48.0 \times 0.80 = 38.4\) km;订单却多三成,从 \(30\) 单涨到 \(39\) 单。表 1 是三种应对方式的实测结果,先摆数字。

表 1 三方案在暴雨日的结果对照

方案 订单池 /单 可完成 /单 总里程 /km 换电 /次 全天耗时 /min 推车 /km 净收益 /元
A 晴天排程硬撑 30 30 45.7 0 483.8 7.3 212.3
B 雨天保守 39 28 38.4 0 332.4 0.0 197.8
C 动态降档 39 35 50.3 1 429.8 0.0 246.4

晴天那套排程单看没问题:\(30\) 单、\(45.7\) km、装进 \(48.0\) km 的电池刚好还剩 \(2.3\) km。可雨天一到,这 \(45.7\) km 就超了 \(7.3\) km——不是超一点,是超出 \(18.9\)%。

1.2 为什么要优化

第一,余量是隐藏的。晴天排程看起来"排满",其实余量只有 \(2.3\) km,占总续航的 \(4.9\)%。任何超过 \(4.9\)% 的续航衰减都会让这套排程失效,而雨天衰减是 \(20.0\)%——差了一个数量级,垮得毫无悬念。

第二,容量不是参数,是决策。换电一次补 \(35.0\) km,花 \(6.0\) min 和 \(3.0\) 元。容量写成 \(E_0\lambda + \Delta E\, n\) 之后,\(n\) 进了右端,约束不再是背包,而是"背包 + 扩容"的混合问题。

第三,时间也是硬约束。多送一单不只是多耗电,还多占 \(6.2\) min 左右。雨天在线 \(430.0\) min,能量够了时间也未必够——两个维度一起卡,才是真实现场。

1.3 Gurobi 如何求解

模型有 \(39\) 个 0-1 变量 \(x_i\) 和 1 个整数变量 \(n \in \{0,1,2\}\),约束 \(2 + 1\) 条,规模极小。关键是把"容量随决策变"这条非线性约束线性化:原式 \(\sum_i d_i x_i \le 38.4(1 + n)\) 右端是变量乘积,改写为 \(\sum_i d_i x_i \le 38.4 + 35.0\,n\) 之后完全线性,Gurobi 直接分支定界,单次求解 \(0.039\) 秒。参数扫描共 \(62\) 次求解,全部在 3 秒内跑完。

2 数学模型

2.1 符号说明

\(I\) 为当日订单集合,\(|I| = 39\);\(d_i\) 为单均往返里程(km),\(w_i\) 为配送费(元),\(t_i\) 为占用时长(min);\(E_0 = 48.0\) 为晴天满电续航,\(\lambda\) 为续航折扣,\(\Delta E = 35.0\) 为单次换电补充里程,\(\tau = 6.0\) 为换电耗时,\(W = 430.0\) 为在线上限,\(c = 3.0\) 为换电机会成本;\(x_i \in \{0,1\}\),\(n \in \{0,1,2\}\)。

2.2 目标函数

\[\max\ \sum_{i\in I} w_i x_i - c\, n \tag{1} \]

收益减换电成本。换电省下的不是钱,是单量——\(c\) 取 \(3.0\) 元是把它折成"三次换电抵一单"的量级,避免模型为了 1 块钱无限换电。

2.3 约束条件

\[\sum_{i\in I} d_i x_i \ \le\ E_0\lambda + \Delta E\, n \tag{2} \]

续航约束。这是本题的核心:右端含决策变量 \(n\),容量随决策变。原始写法 \(E_0\lambda(1+n)\) 是双线性,改成加法形式后线性。\(\Delta E\) 略小于 \(E_0\lambda\)(\(35.0\) 对 \(38.4\)),因为换上的电池不是满电、且要留出回柜的余量。

\[\sum_{i\in I} t_i x_i + \tau n \ \le\ W \tag{3} \]

时间约束。\(t_i = d_i / v + 6.2\),\(v = 16.0\) km/h 是雨天车速。换电同时吃电和时间,这是它唯一的成本。

\[n \le 2,\qquad x_i \in \{0,1\} \tag{4} \]

换电上限。商圈周边换电柜就那几个,一天最多跑 \(2\) 次。

2.4 规模与性质

\(39\) 个 0-1 变量、1 个整数变量、3 条约束,是一维背包加一维"可扩容容量"的变形。它是弱 NP-难:\(n\) 只有 3 个取值,固定 \(n\) 后退化为标准 0-1 背包,可用价值密度 \(\theta_i = w_i / d_i\) 贪心近似;Gurobi 的分支定界在根节点就几乎收敛。

3 Gurobi 求解实现

3.1 建模要点

x = m.addVars(NN, vtype=GRB.BINARY)
n = m.addVar(vtype=GRB.INTEGER, lb=0, ub=nmax)
m.addConstr(gp.quicksum(d[i] * x[i] for i in range(NN)) <= E0 * lam + de * n)
m.addConstr(gp.quicksum(tt[i] * x[i] for i in range(NN)) + TAU * n <= wcap)

一个实现细节:右端含变量时不要写成 \(E_0\lambda(1+n)\)。Gurobi 会把乘积判为非线性,转 QCP 甚至报错;而 \(E_0\lambda + \Delta E n\) 是纯线性的,且语义更清楚——"每换一次电,可用里程加 \(\Delta E\)"。

3.2 求解结果

三方案各解一次:A 用 \(\lambda=1\)、\(n\) 锁 0、时间不限,得到"晴天视角下最优"的那套排程;B 用 \(\lambda=0.80\)、\(n\) 锁 0;C 放开 \(n \le 2\)。

表 2 续航折扣主扫描(单块电池,方案 B 口径)

折扣 \(\lambda\) 雨天续航 /km 可完成 /单 缺口 /单 A 推车 /km A 超时 /min
0.70 33.6 25 14 12.1 125.8
0.75 36.0 27 12 9.7 89.8
0.80 38.4 28 11 7.3 53.8
0.85 40.8 30 9 4.9 17.8
0.90 43.2 31 8 2.5 0.0
0.95 45.6 32 7 0.1 0.0
1.00 48.0 34 5 0.0 0.0

4 结果分析

4.1 结构:余量只有 \(4.9\)%

图 1 续航—里程曲线与晴天排程的击穿点

三条斜线是三种雨强下的"剩余续航 = 起始续航 − 已跑里程"。晴天排程落在 \(45.7\) km,暴雨线在这一点已经是 \(-7.3\),落在横轴以下。直线斜率都是 \(-1\),所以缺口只取决于起点的下移量:起点掉 \(9.6\) km,缺口就是 \(7.3\) km。

图 2 订单池全景:里程—配送费散点(气泡 = 占用时长)

\(39\) 单铺在里程 \(0.94\)—\(1.79\) km、配送费 \(6.37\)—\(7.74\) 元之间。雨天新增的 \(9\) 单(方块)集中在短里程、高单价一侧——这是雨天加价的结果,也是"该保哪些单"的答案:单位里程收益 \(\theta_i\) 高的单必须优先保住。

4.2 结果:三方案的取舍

图 3 三方案的可完成单量与缺口

A 的两根柱子一样高——\(30\) 单看着"全送到了",可代价藏在图外:推车 \(7.3\) km、超时 \(53.8\) min。B 老老实实按 \(38.4\) km 排,只排得出 \(28\) 单,缺口 \(11\) 单。C 把池子里的 \(39\) 单全排上,最后送到 \(35\) 单,靠的是换电 \(1\) 次撑出的 \(73.4\) km 容量。

图 4 按价值密度排序的累计配送费阶梯

三条阶梯的斜率就是价值密度:C 一路爬到 \(249.4\) 元才停,B 在 \(38.4\) km 竖线处被截断在 \(197.8\) 元。B 与 C 的差额 \(51.6\) 元,就是"不肯换电"的代价;而换电只花 \(3.0\) 元。

图 5 续航折扣主灵敏度:可完成单量与推车里程

折扣从 \(1.00\) 掉到 \(0.70\),保守排程的可完成单量从 \(34\) 单滑到 \(25\) 单,几乎线性。点线标出临界折扣 \(0.951\)——只要折扣低于它,晴天排程必然推车;粉区是"无论怎么排都跑不完"的折扣段。

图 6 续航折扣与订单池规模的二维灵敏度

热图把两个同向恶化的变量摆在一起:右下角(折扣高、单量少)最宽松,左上角(折扣低、单量多)最紧。从 \(22\) 单到 \(32\) 单,格子颜色跨了 \(10\) 单——折扣与单量各恶化两成叠起来,可完成的单量掉了近三成。

图 7 在线时长上限对可完成单量的边际效应

在线时长从 \(350.0\) 放到 \(510.0\) min,可完成单量从 \(29\) 升到 \(39\),最后触到 \(39\) 单的池顶——雨天真正稀缺的不是电,是时间。换电次数整段都停在 \(1\) 次——容量早就不是瓶颈,卡住的是时间:\(73.4\) km 的容量全程富余,多给的每一分钟都直接变成单量。

图 8 时间—里程—单量的帕累托前沿与不可行区

横轴是全天地面里程,纵轴是单量。粉色区(\(> 38.4\) km)是单块电池物理上到不了的区域。前沿从左上往右下走:要更多单,就得跑更多路,也就必须换电。B 卡在 \(38.4\) km 的竖直墙上,C 越过墙靠的是 \(\Delta E\)。

图 9 推车里程的蒙特卡洛分布与累计概率

把折扣看成随机变量(均值 \(0.84\)、标准差 \(0.08\)),A 的推车里程分布右偏,均值 \(5.4\) km,推车概率 \(91.4\)%——几乎必然。这意味着 A 不是"风险方案",是"必败方案"。

图 10 三方案的全天耗时构成

堆叠条把 \(430.0\) min 的账算清楚:A 的骑行 \(171.3\) min 加推车 \(109.0\) min,总量 \(483.8\) min 直接冲破上限 \(53.8\) min;C 多花 \(6.0\) min 换电,总量 \(429.8\) min 仍在 \(430.0\) min 之内。换电买的是里程,花的是时间,而时间这里还有富余——所以这笔交易划算。

5 结论

  1. 续航折扣临界值是 $0.951。晴天满负荷排程只剩 \(2.3\) km 余量(\(4.9\)%),任何超过 \(4.9\)% 的衰减都会击穿它;暴雨的 $20.0% 衰减是它的 \(4.1\) 倍。

  2. 硬撑不是"少送几单",是"推车 \(7.3\) km、超时 \(53.8\) min"。推车速度只有 \(4.0\) km/h,\(7.3\) km 要 \(109.0\) min,比送完剩下的单还费时间。

  3. 保守排程的代价是 \(11\) 单。单块电池在 \(38.4\) km 内只能覆盖 \(28\) 单,占池子的 \(71.8\)%。

  4. 动态降档用 \(3.0\) 元和 \(6.0\) min 换回 \(7\) 单,折合每单 \(0.4\) 元成本,远低于单均 \(7.09\) 元的配送费。

  5. 真正该盯的不是"今天下不下雨",是"余量够不够"。晴天排程把电池用掉 \(95.1\)%,这种"刚好够"的排法在任何扰动下都会崩;把电池用量压到 \(76.1\)% 以内、或者干脆把换电写进计划,才是稳态做法。


参考文献

[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:03  小青蛙电气  阅读(2)  评论(0)    收藏  举报