案例 025 和同行换两单:两车换单的指派—路径联合优化
案例 025 和同行换两单:两车换单的指派—路径联合优化
摘要:陈 有 6 单、赵 有 5 单,两条路线互相穿过对方腹地。本文用共享指派变量 \(z_i\) 同时门控两条路线的出入度,建立带基数约束与双边同意约束的两车 VRP,以 Gurobi 求全局最优,并用 462 种 6/5 划分的全枚举独立校验。结果表明:只需换 2 单(A3、B4),合计里程由 29.81 km 降到 25.58 km(省 14.2%),且双方各自都变短(+1.48 / +2.75 km);总里程最优的划分并不等于双方都愿意接受的划分。
关键词:外卖配送;两车VRP;订单交换;指派变量;Gurobi
1 问题提出
1.1 问题是什么
陈 手上有 6 单(A1—A6),同行赵 手上有 5 单(B1—B5),两人出发点相距 0.55 km。11 个客户点撒在荔湾—越秀—天河的 5 km 见方里,两条路线互相穿过对方的腹地:陈 的 A6 在东侧,赵 的 B3 在北侧,赵 的 B4 又在东南角。
把 11 张订单在两人之间重新划分(总单量仍为 6 : 5),各排一条最短巡回,使两人里程合计最小,且谁也不比换单前跑得更远。
表 1 11 张订单的坐标与归属
| 订单 | 东向 /km | 北向 /km | 换前归属 | 到陈出发点 /km | 到赵出发点 /km |
|---|---|---|---|---|---|
| A1 | 1.2 | 1.8 | 陈 | 2.14 | 2.22 |
| A2 | 2.4 | 1.1 | 陈 | 2.69 | 2.45 |
| A3 | 0.6 | 2.9 | 陈 | 2.89 | 3.16 |
| A4 | 3.1 | 2.4 | 陈 | 3.94 | 3.82 |
| A5 | 1.9 | -1.2 | 陈 | 2.39 | 1.82 |
| A6 | 4.0 | 0.9 | 陈 | 4.18 | 3.83 |
| B1 | -0.9 | 2.2 | 赵 | 2.25 | 2.75 |
| B2 | 0.2 | 3.4 | 赵 | 3.31 | 3.65 |
| B3 | 2.8 | 3.6 | 赵 | 4.55 | 4.56 |
| B4 | 3.6 | -0.7 | 赵 | 3.79 | 3.28 |
| B5 | -1.6 | 0.6 | 赵 | 1.58 | 2.13 |
换单前各自的最短巡回:陈 14.04 km、赵 15.76 km,合计 29.81 km。这两个数不是"随便排",是对 6! 与 5! 条顺序全枚举取最小得到的,因此下文的节省量不会掺入排序误差。
1.2 为什么要优化
- 里程是纯支出:11 单的配送费按单结,跑多少公里都只按单算钱,省下的每一公里都是净得;
- 交换必须双方都点头:只要一方变差,这笔交换在现实中谈不成,模型必须写成双边约束而不只是总量最优;
- 单量是刚性承诺:平台按在手单量考核,换单不能变成"把单甩给对方"。
1.3 Gurobi 如何求解
两套弧变量 \(y^{1}_{ij},y^{2}_{ij}\) 加一套共享指派变量 \(z_i\)(\(z_i=1\) 表示订单 \(i\) 归 陈)。\(z_i\) 同时门控两条路线的出入度,是"点是否属于车 1"的开关:
模型 332 个变量、549 条约束,0.27 s 求得最优(MIP gap 0)。两侧的"同意"约束把解限制在不劣于各自基准的区域内。
2 数学模型
2.1 符号说明
客户集 \(C=\{1,\dots,11\}\),车 \(k\in\{1,2\}\) 的出发点记为 \(0_k\);\(d^{k}_{ij}\) 为车 \(k\) 视角的里程;\(s=2.0\) min 为每单服务时长;\(v=18\) km/h;\(T^{\max}=70\) min 为单车时限;\(z^{0}_i\) 为换单前归属。
2.2 目标函数
2.3 约束条件
单量守恒(换单不改变总量):
每点恰好被自己所属的车访问一次,即式 (1);出发点的出入度各为 1:
子回路消除(MTZ):
时刻递推与单车时限:
双方同意(净收益非负):
2.4 规模与性质
11 个客户、2 个出发点、264 条有向弧,变量 332 个、约束 549 条。这是带基数约束的两车 VRP(2-SPRP 的简化),NP-难;但 11 个客户只有 \(\binom{11}{6}=462\) 种 6/5 划分,每种划分的两个 TSP 可全枚举,\(\binom{11}{6}(6!+5!)=388080\) 条巡回,能在一秒内算完——这是本例敢说"全局最优"的底气。
3 Gurobi 求解实现
3.1 建模要点
for k in range(N): # 一个 z 门控两条路线
m.addConstr(quicksum(ya[k+1, j] for j in ...) == z[k])
m.addConstr(quicksum(yb[k+1, j] for j in ...) == 1 - z[k])
m.addConstr(quicksum(z) == 6) # 单量守恒
m.addConstr(kmA <= dA0) # 双边同意:谁也不许变差
m.addConstr(kmB <= dB0)
一条实现细节:同意约束写在里程上,不写在"收益"上。因为单车单量固定为 6 : 5,每单收入与路线无关,净收益只差一个常数,所以"净收益 \(\ge 0\)"与"里程不增加"完全等价——省掉一层换算,也避免正文出现两套口径。
3.2 求解结果
表 2 换单结果
| 指标 | 换单前 | 换单后 |
|---|---|---|
| 陈 的里程 /km | 14.04 | 12.56 |
| 赵 的里程 /km | 15.76 | 13.01 |
| 合计 /km | 29.81 | 25.58 |
| 陈 的单量 | 6 | 6 |
换手的订单是 A3、B4(共 2 单)。合计里程从 29.81 km 降到 25.58 km,省 4.23 km(14.2%);而两侧各自都不劣于换前(陈 +1.48 km、赵 +2.75 km),因此这笔交换双方都愿意做。
4 结果分析
4.1 路线结构
图 1 是换单后的两条路线:蓝线归 陈(6 单)、红线归 赵(5 单),圆圈标出换手的 A3、B4。换的不是"最近的",而是"最不顺路的"——A3、B4 原本要横穿另一位骑手的腹地,交出去以后两条线各自收成一片。

图 1 换单后两人的配送路线
图 2 把每单放进"到陈出发点—到赵出发点"的平面。对角线以上表示离赵更近、以下表示离陈更近;换手的两单(大气泡)都落在对角线的另一侧——几何上早该换,只是原先按接单顺序分派。

图 2 各订单到两个出发点的距离
4.2 换单的代价与收益
图 3 的瀑布把总里程拆开:起点 29.81 km,陈 的路线变化 -1.48 km,赵 的路线变化 -2.75 km,终点 25.58 km。增益全部来自"把远单换成近单",两条线的增减互为镜像,谁都没有被牺牲。

图 3 换单前后的里程分解
图 4 是 陈 的累计里程阶梯:模型顺序 12.56 km,最近邻贪心 18.60 km。同一批订单,光换排序就差 6.03 km(32.4%),说明"顺路"不能靠感觉判断。

图 4 累计里程:最优顺序与最近邻
4.3 灵敏度
图 5 让 陈 的单数从 4 变到 8:总里程在 24.99—28.07 km 之间,但"较弱一方的净节省"在 \(k=6\) 附近穿过 0 线。总里程最小的划分并不等于谈得成的划分——把单量往一边压,另一边必然吃亏。

图 5 总里程与较弱一方净节省随单数的变化
图 6 把单数与车速同时扫:车速越高,整片颜色越浅,但深浅的"分界位置"不随车速移动——最优划分只由几何决定,与跑多快无关。

图 6 总里程关于单数与车速的热图
图 7 收紧单车时限:48 min 时总里程 25.58 km、换手 1 单;放宽到 88 min 时 25.58 km、换手 1 单。时限越紧,越倾向于换单:两条交叉的路线在时间上先撞墙,换开以后各自变短、也各自变快。

图 7 总里程与换手单数随时限的变化
4.4 前沿与分解
图 8 把 462 种 6/5 划分全部画进"陈 里程—赵 里程"平面,虚线是不限换单次数的帕累托前沿,星号是模型解(只许换 1 对)。竖线右侧是"陈 不同意区"(比换前更远),落在里面的划分现实中谈不成。星号在前沿上方,并没有压到前沿上——差的正是"只许换 1 对"这条纪律:前沿最低点 23.37 km 需要换 2 对才够得着。

图 8 462 种划分的帕累托前沿
图 9 是 462 种划分的总里程分布:均值 28.51 km,最优 25.58 km 在左尾,不换单的 29.81 km 落在均值右侧。"随手分"平均要多跑 4.23 km。

图 9 全部划分的总里程分布
图 10 把里程按片区拆开:换单后 陈 的天河片 6.26 km(换前 5.72)、赵 的越秀片 4.58 km(换前 4.24)。换单实质是"片区归位":陈 收缩到东南,赵 收缩到西北,两人各让出一块飞地。

图 10 两人里程的片区分解
5 结论
- 11 单在两人之间只需换 2 单(A3、B4),合计里程由 29.81 km 降到 25.58 km,省 4.23 km(14.2%)。
- 交换对双方都是净收益(陈 +1.48 km、赵 +2.75 km),满足"双方同意",因此在现实中谈得成。
- 用 \(z_i\) 同时门控两条路线的出入度(式 1)是两车换单模型最省变量的写法,避免为每张订单建两套归属变量。
- 单量灵敏度显示:总里程最小的划分(\(k\ne 6\))会让一方变差,"总量最优"与"谈得成"不是同一件事。
- 462 种划分全枚举独立校验:不限换手次数的最优是 23.37 km(2 对),比"只换 1 对"再省 2.20 km,换手次数上限才是效率的主要瓶颈,而不是路径排得好不好。
参考文献
[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.py;数据与结果见同目录 .csv / .json,图见 figs/

浙公网安备 33010602011771号