案例 069 换电顺路做

案例 069 换电顺路做

摘要:换电柜不是目的地。把 12 单的送餐路径与 5 座换电柜放进同一个有向图,柜子与客户点同构、只是收益为 0、停留 3 min,模型自己决定「在哪一单之后拐进去」。三种方案对比:不换电只能跑 6 单、净收入 51.1 元;专程去 2.40 km 外的柜子、全程 64.7 km,跑满 12 单、净收入 109.4 元;顺路插进 0.35 km 处的柜子、全程 58.3 km,同样 12 单、净收入 111.3 元。同一批订单、同一次换电,位置换一下就是 6.5 km、19 min 的差;而顺路换电真正的价值是把单量从 6 单抬到 12 单——多接 6 单、多赚 60.2 元。

关键词:可选站路径;换电位置;电量递推;混合整数规划;绕行成本;灵敏度分析

1 问题提出

1.1 问题是什么

午高峰四个小时,系统推来 12 单,毛收入 130.3 元,跑完要 58.3 km。车的满电续航 42 km,扣掉 15% 安全边际只剩 35.7 km 可用——一管电跑不完全部单,必须换一次电。麻烦在于换电柜不在路线上:最近的柜离第 5 单客户只有 200 m,最远的单子离开柜子有 8.94 km,取餐一趟连柜都见不到。

所以真正要决定的不是「换不换」,而是「在哪一单之后拐进去」。拐进 200 m 外的柜,来回 0.4 km、一分多钟;拐进 2.40 km 外的柜,来回 4.8 km、十几分钟——同样的电,代价差十倍。

表 1 八单代表数据(全 12 单见 data_069.csv,柜距取最近换电柜)

订单 区域 \(D_{i}\) /km \(w_{i}\) /元 \(q_{i}\) /份 \(\delta_{i}\) /km 顺路柜 所在段
O01 天河 4.20 9.5 2 3.03 否 1
O03 越秀 10.23 8.5 2 3.90 否 2
O05 海珠 15.21 12.5 3 0.20 是 2
O06 海珠 17.68 10.0 2 3.67 否 2
O08 番禺 18.98 9.0 2 0.35 是 2
O10 越秀 13.67 11.5 3 5.96 否 1
O11 天河 9.84 8.8 2 6.25 否 1
O12 天河 10.10 10.5 3 8.94 否 1

1.2 为什么要优化

第一,不换电直接砍掉一半单。12 单的路径里程 58.3 km 需要 139% 的电,一管电只有 85%,图 3 里不换电只完成 6 单、51.1 元。

第二,「专程」和「顺路」的差别被低估了。专程方案总里程 64.7 km,比顺路多 6.5 km,按 20 km/h 折 19 min,按 0.30 元/km 折 1.9 元;多跑的里程本身还要耗电。

第三,换电点选错会挡掉后面的单。换电把电量复位到 100%,复位之后剩下的路必须在一管电内跑完;换早了浪费电,换晚了电压到 15% 以下,模型里 \(e_{i}\ge e_{\min}\) 是硬约束,违反就是推车。

1.3 Gurobi 如何求解

决策三组:\(y_{ij}\in\{0,1\}\) 走不走弧 \((i,j)\)、\(x_{i}\in\{0,1\}\) 接不接单、\(w_{s}\in\{0,1\}\) 用不用柜 \(s\)。12 个客户点加 5 个候选柜加起终点共 19 个节点,弧变量约 323 个。电量 \(e_{i}\) 沿弧递推,经过柜点时用「复位项」\((100-e_{i})w_{i}\) 线性化(式 4);子回路用 MTZ 割掉(式 5)。柜子与客户点在模型里完全同构,唯一区别是经过它时收益为 0、耗电被清零、时间加 3 min——这就是「可选站」写法的全部技巧,一套 \(y_{ij}\) 同时管路径与换电。

规模不大,但电量递推让 LP 松弛变松。三方案与 32 次扫参求解合计 47 s 内跑完,主方案在 1.5 s 内证到 gap 0。

2 数学模型

2.1 符号说明

\(I\) 为客户点集合(\(|I|=12\)),\(S\) 为候选换电柜集合(\(|S|=5\)),\(0\) 为取餐区、\(n+1\) 为回程终点(与 \(0\) 同址);\(A\) 为可行弧集;\(d_{ij}\) 为弧长,\(D_{i}\) 为订单 \(i\) 到取餐区的直线距离,\(\delta_{s}\) 为柜 \(s\) 到最近客户点的距离,\(\bar{\delta}\) 为顺路阈值(本案 0.5 km);\(w_{i}\) 为单收入、\(\tau_{i}\) 为单占用时长;\(R\) 为满电续航、\(e_{i}\) 为到达 \(i\) 时的电量、\(e_{\min}\) 为安全边际、\(\tau_{s}\) 为单次换电耗时、\(\kappa\) 为换电次数上限;\(c_{k}\) 为里程成本、\(c_{s}\) 为换电固定成本、\(v\) 为车速、\(T\) 为班次时长。

2.2 目标函数

\[\max\ Z=\sum_{i\in I}w_{i}x_{i}-c_{k}\sum_{(i,j)\in A}d_{ij}y_{ij}-c_{s}\sum_{s\in S}w_{s}\tag{1} \]

收入按单计,里程按 0.30 元/km 折(电费加折旧),换电按 1.5 元/次折(3 min 的机会成本)。里程项是这一例的关键:它让「专程」与「顺路」在同一把尺子上比较,专程方案多跑的 6.5 km 直接从利润里扣。

2.3 约束条件

\[\sum_{j:(i,j)\in A}y_{ij}=x_{i},\quad \sum_{j:(j,i)\in A}y_{ji}=x_{i},\qquad \sum_{j}y_{0j}=\sum_{j}y_{j,n+1}=1,\qquad \sum_{s\in S}w_{s}\le \kappa\tag{2} \]

每个接了的单必须一进一出;起终点各一条弧;换电次数不超过 \(\kappa\)(本案 1 次)。

\[\sum_{j:(i,j)\in A}y_{ij}=w_{s},\quad \sum_{j:(j,i)\in A}y_{ji}=w_{s},\qquad y_{ij}=0\ \ \text{若}\ \delta_{s}>\bar{\delta}\ \text{或}\ s\notin S\tag{3} \]

式 (3) 是「可选站」的开关:柜子被选中才一进一出,且只有 \(\delta_{s}\le\bar{\delta}\) 的柜子才进入候选集——这一条把「顺路」写成了可行性约束,而不是目标里的软惩罚。阈值之外的柜子在专程方案里才放开,此时它的插入代价 \(d_{a,s}+d_{s,b}-d_{a,b}\) 自动接近 \(2\delta_{s}\)。

\[e_{j}=e_{i}-\frac{100\,d_{ij}}{R}+(100-e_{i})\,w_{i},\qquad e_{i}\ge e_{\min}\ \ (\forall i\in I\cup S)\tag{4} \]

到达 \(j\) 的电量等于到达 \(i\) 的电量减去这段耗电;若在 \(i\) 处换了电,则先复位到 100% 再扣。\((100-e_{i})w_{i}\) 是双线性项,用两条大 M 约束替代:\(w_{i}=1\) 时强制 \(e_{j}=100-100d_{ij}/R\),\(w_{i}=0\) 时强制 \(e_{j}=e_{i}-100d_{ij}/R\)。安全边际对每个访问点(含柜)生效。

\[u_{j}\ge u_{i}+1-n\,(1-y_{ij}),\qquad \sum_{i\in I}\tau_{i}x_{i}+\tau_{s}\sum_{s\in S}w_{s}+\frac{60}{v}\sum_{(i,j)\in A}d_{ij}y_{ij}\le T\tag{5} \]

MTZ 消子回路(\(u_{i}\) 为访问序);时间约束把送餐停留、换电、骑行三项加起来不超过 240 min。

2.4 规模与性质

19 个节点、323 个弧变量、12 个选单变量、1 个换电开关,约束约 700 条。这是一条带电量约束的奖金收集 TSP(prize-collecting TSP with battery),NP 难;但本案节点少、电量是路径的单调函数,分支定界秒级就能证到 gap 0。与经典燃料约束 VRP 的差别在于:柜子是可选的中间点,插不插由模型定,而不是预先给定的固定站点。

3 Gurobi 求解实现

3.1 建模要点

柜子与客户点共用一套 \(y_{ij}\),靠节点编号区间区分角色:

for k, s in enumerate(stas):                    # 柜点:一进一出由 w_s 控制
    md.addConstr(gp.quicksum(yv[a, b] for (p, b) in yv if p == a) == ws[k])
for (a, b) in yv:                               # 电量递推,柜点带复位项
    if a >= 1 + K:
        md.addConstr(e[b] >= e[a] - c - ME*ws[k] - ME*(1 - yv[a, b]))
        md.addConstr(e[b] >= 100 - c - ME*(1 - ws[k]) - ME*(1 - yv[a, b]))

一个实现细节:换电点的两组约束必须互补门控——「不换电」那一对用 \(w_{s}\) 放松、「换电」那一对用 \(1-w_{s}\) 放松。两对同时生效会把 \(e_{j}\) 逼到 \(100-c\) 与 \(e_{i}-c\) 两个值上,只要换电前电量不是满的就不可行,表现出来是「模型宁可少接单也不换电」。另一个坑是起终点同址——若共用一个节点,出度与入度会互相污染,必须拆成 \(0\) 与 \(n+1\) 两个节点。

3.2 求解结果

表 2 三方案结果($R=42$ km,$\tau_{s}=3.0$ min,$\delta\le0.5$ km,$\kappa=1$)

方案 单量 总里程 /km 毛收入 /元 净收入 /元 用时 /min 换电柜
不换电 6 34.0 61.3 51.1 117 —
专程去换 12 64.7 130.3 109.4 227 C5(2.4 km)
顺路插入 12 58.3 130.3 111.3 208 C2(0.35 km)

三行读下来:不换电 6 单 / 51.1 元;专程去换 12 单 / 109.4 元、64.7 km;顺路插入 12 单 / 111.3 元、58.3 km。换电本身只值 1.5 元,值钱的是位置:专程比顺路多跑 6.5 km、多花 19 min、少赚 1.9 元。

4 结果分析

图 1 顺路换电方案的实际路径:第 1 段 5 单,在柜 C2 换电后跑第 2 段 7 单

4.1 路径与换电点 图 1 把顺路方案的完整路径画出来:第 1 段 5 单向东扫到柜 C2(离客户点 0.35 km),换电后第 2 段 7 单绕回取餐区。柜 C2 几乎压在 O08 客户身上(0.35 km),箭头在这里只多拐了一个小三角——这一段就是全部的「绕行」,0.00 km。 对比图里南侧的柜 C5(2.40 km 外),换电点若换成它,同样 12 单要多跑 6.5 km。

图 2 订单到最近换电柜的距离与单收入的散点,气泡面积为份数

4.2 绕行—收益画像 图 2 横轴是订单到最近柜的距离、纵轴是单收入、气泡是份数。2 单的 \(\delta_{i}\le0.5\) km(绿色),其余 10 单在 0.6—8.94 km 之间(灰色)。关键不是「哪单收入高」,而是「哪单旁边有柜」:O05 收入 12.5 元只排中游,但它旁边的柜距只有 0.20 km,是整条路线上少有的免费换电机会。

图 3 三种换电方案的单量、净收入与总里程对比

4.3 三方案对比 图 3:6 单 / 51.1 元、12 单 / 109.4 元、12 单 / 111.3 元。不换电被一管电卡死在 6 单;一旦允许换电,单量天花板顶到 12 单,剩下的差别全是位置成本。专程与顺路的净收入差 1.9 元、里程差 6.5 km——不是订单质量的差别,是柜子位置的差别。

图 4 累计里程与剩余电量:顺路换电把曲线在零绕行处拉回 100%

4.4 电量曲线 图 4 横轴累计里程、纵轴剩余电量。不换电那条(点线)在 34.0 km 处停住,剩余 19.0%,再走一单就破 15% 线;专程那条(虚线)在 31.6 km 处有一个 100% 的竖跳,跳之前的谷底是 21.3%——绕行本身耗电,为了换电先把电用在路上,这是「专程」的隐藏成本。顺路那条(实线)在 27.6 km 处竖跳,谷底 27.1%,跳前后几乎不占横轴。

图 5 满电续航对单量与方案总里程的影响

4.5 续航灵敏度 图 5 左轴单量、右轴总里程。续航从 30 km 提到 60 km,顺路方案从 7 单升到 12 单并很快封顶,不换电方案从 3 升到 9 单、一路缓升——续航越短,换电越值钱;越短,两条线的差越大。右轴的总里程随续航上升而缓慢增加,说明长续航下模型愿意为多接单走更远的路。

图 6 续航 × 可用柜距阈值的热图,黄框为本案参数

4.6 续航 × 柜距阈值 图 6 是 4×4 热图,行是可用柜距阈值 \(\bar{\delta}\)、列是续航。同一列自上而下(续航 42 km 列):109.7 → 111.3 → 111.3 → 111.3 元,阈值从 0.25 km 放到 2.40 km 只值 1.7 元;同一行自左向右(阈值 2.40 km 行)从 80.1 到 111.3 元,值 31.2 元。柜距阈值的作用远小于续航:多记十座远处的柜,不如把电池换新。 本案参数(42 km、0.5 km)落在拐点附近(星标)。

图 7 平均车速对净收入与单量的影响(第三维)

4.7 车速(第三维) 图 7 左轴净收入、右轴单量,横轴是平均车速。从 15 km/h 提到 23 km/h,净收入从 94.4 元升到 111.3 元、单量从 10 单升到 12 单,23 km/h 之后完全走平。这是一条「先断后平」的曲线:车速低于 17 km/h 时骑行时间挤占班次,被迫少接 2 单;高于 17 km/h 后瓶颈交回给电量,再快也没用——与图 5 的续航曲线互为镜像,一个管「一管电跑多远」,一个管「四小时跑多远」。

图 8 里程预算与可接单量的前沿,灰色为单池上界以上的不可达区

4.8 里程—单量前沿 图 8 横轴是路径里程预算、纵轴是能给到的最多单量。预算 28 km 时只能 4 单,60 km 时给到 12 单(单池上限 12 单,灰区是上界以上不可达)。前沿在 36—52 km 之间最陡:每多 8 km 预算能换回 1—3 单,超过 52 km 后平掉——本案实际里程 58.3 km 已经站在平的这一侧,说明里程不是本案的瓶颈,电量分配才是。

图 9 订单到最近换电柜距离的分布与累计占比

4.9 柜距分布 图 9 是订单到最近柜的距离直方图加累计曲线。12 单里只有 2 单在 0.5 km 内,中位数 3.10 km,最长 8.94 km——柜子集中在送货带的两三个角落。累计曲线在 0.5 km 处只爬到 17%,也就是说八成订单旁边没有柜——「顺路」不是普遍机会,而是少数订单才有的运气。这也解释了图 6 里柜距阈值那一条为什么几乎不值钱:阈值从 0.25 放到 2.5 km,能用的柜从 1 座变成 5 座,但真正贴着路线的那一座一直是同一座。

图 10 顺路方案逐单插入边际贡献,虚线为均值

4.10 逐单边际贡献 图 10 按插入边际(\(w_{i}-c_{k}\cdot\)插入距离)从高到低排。最高 13.42 元、最低 8.04 元、均值 10.45 元,极差只有 5.38 元。12 单的边际贡献高度平均,说明最优解不是「挑肥拣瘦」挑出来的,而是「电够了就全接」——单量的天花板是电量,不是订单质量。

5 结论

  1. 换电要顺路做,专程的代价可以精确到公里和分钟。 同样 12 单、同样一次换电,专程去 2.40 km 外的柜要多跑 6.5 km、多花 19 min、少赚 1.9 元(图 3、图 4)。绕行不只是一段路,它同时吃掉电量和班次时间。
  2. 顺路换电真正买回的是单量。 不换电 6 单 / 51.1 元,顺路换电 12 单 / 111.3 元,多 6 单、多 60.2 元;1.5 元的换电固定成本可以忽略,6 单才是主收益。
  3. 柜子应该建成「客户点的邻居」,而不是「目的地」。 把柜与客户点同构进同一个 \(y_{ij}\) 图,模型自己算出绕行 0.00 km 的插法;柜距阈值从 0.25 放到 2.5 km 只值 1.7 元(图 6),位置比数量重要。
  4. 最优换电点落在「两段里程的均衡点」上,而不是最近的那座柜。 本案最近的柜离客户 200 m(柜 C1),模型却在 0.35 km 的柜 C2 上换电,因为切分点要卡在总量程的一半附近;换完后谷底 27.1%,仍高于 15% 硬线(图 4)。
  5. 瓶颈是电量,不是里程、不是柜子数量。 里程—单量前沿在 58.3 km 处已经走平(图 8),车速到 17 km/h 以上不再掉单(图 7)——要提升单量,先换电池,再谈记柜子。

参考文献

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

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