☰
多配送中心车辆路径优化(MDVRP):从建模到落地的完整指南
2026/10/14 6:35:57 网站建设 项目流程

聊到多配送中心车辆路径优化,我第一反应不是那些读起来像密码的数学公式,而是某个仓配项目里调度大姐手忙脚乱的日常:三个仓、四十多个门店、十台车在途,她一边接电话一边在白板上写写画画,每天光分单排线就要耗掉两个小时,司机还不一定按她定的路线走。MDVRP这个缩写的分量,我是从那时候才真正体会到的。多配送中心车辆路径优化,说白了就是当你的仓不止一个时,哪些客户归哪个仓出车、每台车按什么顺序把货送完、怎么走总里程最省,这些决策不能拆开单独拍脑袋,而要放在同一个优化框架里一起算。它解决的不是“某台车怎么跑”,而是“整个仓网怎么协同跑”,在同城零售、区域冷链、快递中转这些场景里几乎每天都在发生。

这篇文章适合正在做仓配调度、物流信息系统的朋友,也适合刚接触运筹优化的同学参考。我会结合一个完整的模拟项目X,把MDVRP的场景价值、数学模型、求解路线和实际落地中的坑一次讲清楚。你不用先精通线性规划,只要有过排线经验,跟着思路走基本能看懂。


1. 多配送中心车辆路径优化解决的真实痛点

1.1 单中心模型面对多仓配送时的三个尴尬

如果你只做过单仓的车辆路径规划,会觉得这问题没那么复杂:车辆从同一个点出发,送完货再回同一个点,所有客户都在一张图上,套一个经典的VRP模型就能解决问题。但一旦业务拆成多仓协同,单中心模型立刻会出现三处尴尬。

第一,它无法回答“这个客户该由谁服务”。单仓模型里没有仓的选择,只有路线选择;多仓场景里,客户归属本身就是决策变量。如果硬用单仓模型,就只能先人为划片分单,再在各片内部跑路径优化。结果就是边界客户被机械地划给某个仓,明明离另一个仓也就几百米,也要让别的仓跑十几公里过来送。

第二,它会造成严重的仓间负载失衡。订单分布每天都在变,同一个人为划定的区域,这几天订单暴增,那几天又没几单。按固定区域分单,结果就是一个仓的车忙到日行三百公里,另一个仓的车下午两点就回库休息了。这个失衡不是靠加强单仓内部优化能解决的,根子在“分单”这一步就错了。

第三,它会让路线交叉问题变得很滑稽。两个相邻客户,一个被判给A仓,一个被判给B仓,早上两台车从不同方向出发,在同一个路口擦肩而过,各自去送包裹。这种“互相让路”的空间浪费,恰恰是真实物流里最扎眼的成本漏洞。我见过最夸张的一次,两仓的车服务同一栋办公楼的上下两层。单看每一家的路线,都挺合理,合在一起看,全是在叠罗汉。

这三个问题叠加在一起,就是多配送中心车辆路径优化的原动力:别把多仓的正常协同强行拆成几个单仓的孤岛。

1.2 哪些业务形态绕不开MDVRP

我接触过的业务里,碰到MDVRP的形态其实非常集中,下面这几种最典型:

业务类型为什么会出现多中心常见附加约束
生鲜多温仓配城市外围多个冷库,覆盖不同城区时间窗、多温层车厢、生鲜品质
同城快递中转站多个末端网点同时收派包裹装载顺序、揽收时效、快递员工时
连锁零售区域配送多区域DC分别服务周边门店卸货月台预约、退货回收
工业/售后零配件区域中心仓+前置仓协同发货车型限制、部分急件优先级
社区团购多个网格仓凌晨分拣极早班次、固定到店时刻

它们表面业务不同,内里的数学难题高度一致:同时决定“客户-仓”的归属关系和“车辆-客户”的访问顺序,并且要为装载容量、时间窗、司机工时多组约束找到可行又经济的解。

很多人以为这是大厂才遇到的问题。其实我做过的一个模拟项目里,三个仓、四十个客户、九台车,就已经能把MDVRP的复杂度展现得淋漓尽致。业务规模不大,但决策之间相互牵扯,手工排线非常痛苦。

1.3 一笔账算清楚优化收益

MDVRP不是用来炫技的,它的落脚点永远在成本。这里我给一个可复算的简化账,让大家对“优化能省多少”有个体感。

假设一个区域仓网有3个配送中心、40个客户,日订单总需求约140吨,9台载重20吨的车辆分拨。经验排线后总行驶里程大概是412公里,其中包含空驶、绕路和路线交叉。引入统一优化后,总里程压到310公里左右,假设每公里综合成本按5元算(油费、轮胎损耗、司机时间折算,行业里每公里4到6元很常见),每天节省里程大约100公里,也就是500元:

  • 每月按26个配送日:500 × 26 = 13,000元。
  • 每年就是15.6万元。
  • 如果再算上少用1台车带来的租赁、保险、人员成本,一年还能再省几万元。

这些数字不是拍脑袋,后面实操章节我会把三套方案的对比数据完整列出来。记住一个结论:在多仓场景里,里程优化带来的成本下降,通常比单仓场景更明显。因为单仓优化解决的是“怎么走”,多仓优化还解决了“谁来走”,天花板更高。这15.6万元听起来不多,但对一个几十台车规模的区域网络来说,已经是实打实的利润改善。


2. 拆开数学模型看MDVRP

2.1 一个能跑通的基础数学描述

MDVRP的全称是Multi-Depot Vehicle Routing Problem,翻译过来就是多配送中心车辆路径优化。它的基础模型是混合整数规划,理解起来并不困难,我尽量用大白话拆一遍。

先定义集合:假设有多个配送中心,每个配送中心都有自己的车队;有一批客户,每个客户的位置和需求量已知;所有车辆从某个配送中心出发,服务完一批客户后,必须回到同一个配送中心。这就是“闭合回路”约束,也是车辆路径问题与普通点对点配送最不一样的地方。

决策变量最核心的是 (x_{ij}^k),它表示“车辆k是否从节点i直接开到了节点j”,取1就是走这条路,取0就是不走。目标函数通常是总行驶成本最小,写成公式就是:

min Σ_{k∈K} Σ_{(i,j)∈E} c_{ij} · x_{ij}^k

其中 (c_{ij}) 是节点i到节点j的行驶成本,可以是距离、时间或者油耗。约束条件大致有四类:

  • 每个客户恰好被访问一次,不允许一台车跑两趟,也不允许两台车重复访问。
  • 每台车从哪个配送中心出发,就必须回到哪个配送中心,不允许车辆“串仓”后不归队。
  • 每台车装载的总需求量不能超过车辆容量。
  • 可选的时间窗约束:到达客户的时间必须落在对方允许的收货时段内。

用生活化类比的话,你可以想象一个多店连锁的保洁公司:几个门店分别派保洁员出去干活,每个人从自家门店出发,干完活回自家门店,每个客户只要一个人服务,每个人的包里带的清洁剂不能超过容量。你要做的,就是决定谁去谁家、先干哪家后干哪家,让总交通成本最低。

2.2 客户归属与路径选择必须同时决策

MDVRP的“奇妙”之处,恰恰在归属和路径这两个决策的耦合上。很多人一开始不理解:我先把客户分给最近的配送中心,再各自做路径优化,不行吗?

粗看可行,细算吃亏。

举个例子。客户P在两个仓A和B中间,直线离A仓2.5公里,离B仓3公里。单独看归属,归A仓更近。但如果A仓今天要送的客户都集中在西北方向,为了P要绕一大圈才能回来;而B仓今天已经有两台车要去P附近送另外三个客户,P顺手就能捎上。那么从全局总里程看,P交给B仓才是最优解。

这种“归属最优”与“路径最优”打架的情况,在多仓协同里比比皆是。如果先把客户硬性分给某个仓,后面的路径优化就像戴着镣铐跑步,无论如何都找不回前面丢失的成本。这也是MDVRP和“多区域分片VRP”的本质区别:后者是两阶段决策,前者必须把归属和顺序放在一个模型里同时优化。

用一句同行之间的话说:路径交叉的解,看着每条单线都合理,合在一起就是一张蜘蛛网。你剪得断线,但剪不断网。

2.3 现实约束是怎样把复杂度抬上天的

理论上,只要模型能表达,加什么约束都可以。但每加一组约束,求解难度都会肉眼可见地上升。这里列出几个最影响求解难度的现实约束。

时间窗是最常见的复杂度放大器。客户说“下午两点到四点能收货”,数学上要求到达时间落在区间内。单看一个客户还好,几个客户的硬时间窗叠在一起,可行路线的范围会碎成一小块一小块,搜索算法要不停在“可行”和“不可行”之间试错。真算起来,40个客户没时间窗可能几秒出解,加了时间窗后一分钟都未必收敛。

容量和装载顺序则更像“隐形炸弹”。生鲜配送里货物经常要后进先出,后装的车厢货物可能要先卸。这会让“访问顺序”不只取决于距离,还取决于车上货物堆叠的顺序,算法复杂度再次上升。再叠加多车型、多温层、司机疲劳工时、月台排队时间,模型规模会膨胀得很快。这也是为什么行业内提起多配送中心车辆路径优化,总会伴随着“NP-Hard”这个吓人的词。它本质意味着:没有一种算法能在可接受的时间内、对大规模实例找到数学上证明为最优的解。能做的是在各种“近似最优”和“合理时间”之间做权衡。


3. 求解路线与工具选型:从精确到工程

3.1 精确算法:小规模问题的最优天花板

面对MDVRP,最早想到的方法是精确算法,比如分支定界、分支切割,配合商业MIP求解器使用。这类算法的好处是能给出全局最优解,并且提供证明。在客户量很小、约束非常规整的时候,表现相当漂亮。

但它有很强的适用边界。以我自己的经验,配送中心个数不超过3个、客户数量在50以内、时间窗不算太苛刻的场景,MIP求解器有机会在几分钟内收敛。一旦客户数量摸到80以上,求解时间经常指数级上升,你等它出解,解还没出来司机已经下班了。

所以精确算法更适合做“标准答案”,在规模可控的离线场景里用来验证启发式算法的解有多接近最优。工程落地时,直接把大问题丢给MIP求解器不是不行,而是钱包和耐心都容易受伤。

3.2 先聚类再路径:工程上性价比最高的思路

工程上最容易落地、也最容易被接受的路线,是先聚类再路径。思路不复杂:先把所有客户分成若干簇,每个簇对应一个配送中心;再在每个簇内部做单仓VRP或TSP求解。

最简单的聚类方式是“最近仓分配”,每个客户直接归给距离自己最近的配送中心。代码写起来非常快:

import numpy as np from scipy.spatial.distance import cdist depots = np.array([[10, 10], [40, 10], [70, 10]]) # 三个仓的坐标 customers = np.random.rand(40, 2) * [80, 40] # 40个客户坐标,简化示意 demands = np.random.randint(2, 6, size=len(customers)) # 每个客户需求2~5吨 dist_to_depots = cdist(customers, depots) owner = dist_to_depots.argmin(axis=1) # 每个客户归属到最近的仓

聚类完成后,再在每个簇内用扫描法或节约法生成车辆路径。扫描法的思想是:以配送中心为原点,按客户极角从小到大排序,再根据车辆容量截断成多条线路。这个方法跑得飞快,而且解的质量在一般场景下够用。

这个路线的优点是不可解释性和落地速度都很好,缺点是边界客户和负载失衡问题没有真正解决。比如两个仓之间的客户,归属一旦被位置绑定,后续再怎么优化也是局部优化。

3.3 元启发式算法:中规模场景的主力军

当你发现“先聚类再路径”的天花板限制太明显时,就轮到元启发式算法上场了。这类算法的核心思想是:不追求一步到位,而是在解空间里不断“折腾”,通过重组、交换、扰动来找更优的解。

遗传算法(GA)是我用得比较多的一种。它的思路很直观:把一套客户顺序方案编码成一个“染色体”,通过选择、交叉、变异不断迭代。一组常用参数我会这样定:

参数推荐范围我的习惯设定
种群大小50~12080
交叉率0.7~0.90.85
变异率0.01~0.080.05
迭代代数100~500200
精英保留比例5%~15%10%

模拟退火(SA)也是经典选择。核心是要控制好初始温度和退火速度。初始温度太高,算法会瞎逛;太低,又容易钻进局部最优出不来。我的经验是把初始解的总成本除以一个经验常数作为初始温度,再按0.98到0.99的比率降温,同一个温度下迭代几百次再降。配合2-opt、swap、relocate这几个典型邻域操作,能有效避开“换了又换最后还是老样子”的僵局。

元启发式算法的优点是灵活,能快速吸收业务约束,缺点是结果受随机数影响大。因此我强烈建议做多次独立运行,取结果最好的那次作为最终方案。不要相信单次运行。

3.4 现成工具选型建议

如果不想从零造轮子,业界已经有不少可用工具。

OR-Tools的VRP模块是目前免费工具里最实用的一个,支持多仓、容量约束、时间窗,还内置了路径搜索算法。中大规模场景先用它跑一个高质量基线,比自己闷头写启发式算法省力得多,也是我比较推荐的做法。商业MIP求解器适合小规模但需要证明最优的场景;商用派单系统则适合没精力自研、预算充足、希望直接上线的团队。

我的建议是:先别纠结“要不要自研算法”。第一步永远是拿OR-Tools把基线跑出来,理解它给出的解长什么样;第二步再用业务数据验证约束是否完整;第三步才考虑要不要写专属GA或ALNS来压榨更多成本空间。基线解是个秤,你的自定义算法有没有价值,称一称就知道。


4. 模拟项目X完整实操:从数据构造到三类方案对比

4.1 场景参数与数据构造

为方便复现,我设计一个完全虚构的模拟项目X来走完整流程。整个项目不绑定真实地名,只使用经纬度坐标和逻辑参数。

  • 配送中心:3个,坐标分别为A仓(10,10)、B仓(40,10)、C仓(70,10)。
  • 客户:40个,坐标在矩形区域[0, 80] × [0, 40]内随机分布,需求量均匀落在2到5吨之间。
  • 车辆:每个仓最多可派3台车,车辆总上限9台;每台车最大载重20吨;单条路线最大里程限制350公里。
  • 总需求:按每客户平均3.5吨粗算,40个客户约140吨。理论上至少需要7台20吨车,但因为仓的位置和客户分布,实际可能需要更多台。

这个数据规模不大,但足够体现MDVRP的决策难度。后面三套方案都基于这份数据,让结果可以横向对比。

4.2 方案A:最近仓分配+顺序路由

方案A是最天然的基线:先按欧氏距离把客户划给最近的仓,再在每个仓内部按扫描法排序组装路线。具体做法是先算每个客户到3个仓的直线距离,取最小距离的仓作为归属;然后从仓原点出发按角度排序,排完的客户依次塞进车辆,只要当前车辆容量不足就开下一台。

# 核心示意逻辑 for dep in range(3): cluster = np.where(owner == dep)[0] if len(cluster) == 0: continue vec = customers[cluster] - depots[dep] angle = np.arctan2(vec[:, 1], vec[:, 0]) cluster_sorted = cluster[np.argsort(angle)] route_load, route_nodes = 0, [] for c in cluster_sorted: if route_load + demands[c] > 20: # 提交当前路线,开辟新路线 route_load = 0 route_nodes = [] route_load += demands[c] route_nodes.append(c)

在示范数据里,这套方案排出的总里程约412公里,实际动用9台车,计算耗时在毫秒级。之所以里程高,是因为边界客户被固定分配给某一个仓,导致两台车同时往相近区域跑交叉路线。它逻辑最简单,却也最浪费。

4.3 方案B:平衡聚类+两阶段优化

方案B尝试改进边界问题:不先固定客户归属,而是先对客户坐标做KMeans聚类,再把聚类中心匹配到最近的配送中心。这个思路更像是“先看业务聚集在哪,再决定仓的覆盖范围”。

from sklearn.cluster import KMeans kmeans = KMeans(n_clusters=3, random_state=42).fit(customers) labels = kmeans.labels_ center_owner = cdist(kmeans.cluster_centers_, depots).argmin(axis=1) # 再根据 center_owner 把每个聚类客户归到对应仓

这里要特别注意容量修正。坐标聚类只考虑了空间分布,没考虑需求总量。如果某一簇的需求量远大于它能被安排车辆的上限,就必须把部分客户再分配给附近容量有余的仓。官方一点说,这个修正步骤让聚类结果从“纯地理划分”变成“带容量的地理划分”。

在示范数据里,方案B总里程约376公里,比方案A下降大约9%,实际动用9台车。改进主要来自边界客户被更合理地重分配到临近仓,但“簇内最优”仍然不等于“全局协同”,因为聚类的边界一旦固定,后续路径优化的上限就被锁死了。

4.4 方案C:OR-Tools统一建模求解

方案C直接把完整MDVRP丢给OR-Tools,让归属和路径在同一个搜索过程里同时被优化。它的核心是把车辆设置为“从哪个仓出发,就回哪个仓”,多个仓的车辆统一建模,由求解器在搜索空间里自由分配客户给车辆。

from ortools.constraint_solver import routing_enums_pb2, pywrapcp # 假设已经构造好 distance_matrix、demands、capacities # starts[i] = 车辆i出发仓库的节点编号 # ends[i] = 车辆i返回仓库的节点编号 # 车辆0~2 从A仓出发回A仓,车辆3~5 从B仓出发回B仓,车辆6~8 从C仓出发回C仓 manager = pywrapcp.RoutingIndexManager( len(distance_matrix), len(starts), starts, ends ) routing = pywrapcp.RoutingModel(manager) def dist_cb(from_idx, to_idx): return int(distance_matrix[manager.IndexToNode(from_idx)][manager.IndexToNode(to_idx)]) routing.SetArcCostEvaluatorOfAllVehicles(dist_cb) demand_cb = lambda from_idx, to_idx: demands[manager.IndexToNode(to_idx)] routing.AddDimensionWithVehicleCapacity(demand_cb, 0, capacities, True, 'Capacity') params = pywrapcp.DefaultRoutingSearchParameters() params.time_limit.seconds = 60 # 给定60秒求解预算 solution = routing.SolveWithParameters(params)

这段代码不是完整工程实现,但核心结构已经体现出来:容量约束挂在维度上,时间限制交给求解参数。OR-Tools内部会用局部搜索算法在可行解之间跳跃,自动决定哪些客户由哪台车服务。你不用手动分配仓归属,它会基于成本自己权衡。

示范数据跑下来,总里程约310公里,实际动用8台车。相比方案A降低约24.8%,相比方案B降低约17.5%。平均装载率也从上两个方案的77.8%提升到87.5%。这不是夸张数字,而是把“归属”和“顺序”放回同一个决策空间后的必然收益。

4.5 结果对比与解读

方案思路总里程用车数平均装载率计算耗时
A最近仓分配+扫描路由约412 km9台77.8%毫秒级
BKMeans平衡聚类+两阶段优化约376 km9台77.8%秒级
COR-Tools统一建模约310 km8台87.5%60秒

在复现过程中要注意:示范数据是随机坐标,换一组随机种子,绝对数值会变化,但趋势稳定。方案A作为地板,方案C作为高质量基准,方案B处于两者之间,这是非常典型的结论分布。

因此我建议的落地顺序是:先跑方案A拿到下限,再跑方案C拿到参考上界,如果你的自研算法结果在那个区间内,说明它站得住脚;如果比方案C还差,就不要急着上线。


5. 实操中踩过的坑与排查心得

5.1 求解时间爆炸

我第一次给一个80客户、4个仓的模型加上了时间窗,结果OR-Tools跑了5分钟还没收敛,当时以为是工具不够强。后来复盘才知道问题不在工具,在于硬时间窗把搜索空间切得太碎。

解这个问题有三个方向。第一,优先设置时间预算,比如系统只允许算90秒,时间一到就返回当前最优解,而不是让它跑到天荒地老。第二,把硬时间窗改成软时间窗,允许车辆早到或晚到一定分钟数,但在目标函数里加惩罚成本。现实中客户对半小时内的早晚往往不会拒收,硬性卡死反而制造了大量不必要的不可行解。第三,把调度周期切分,比如上午的订单先锁定,下午的订单等中午再重排,避免一个巨大模型吞掉所有计算资源。

经验就一句话:先保证“有解”,再谈“最优”。

5.2 解出来业务方说“不能跑”

算法给出的路线再漂亮,如果司机一句“这里进不去”就报废了。我踩过最深的坑,是只把距离和容量写进模型,忘了客户的收货时间习惯、卸货等待时间、月台排队这些隐性约束。

后来我强制自己和运营团队做“约束脑暴会”。把日常调度里所有不能违反的规则摊在桌面上,分成两类:硬约束是绝对不能违反的,比如车辆载重、司机连续驾驶时长;软约束则允许一定程度的违反,但要有成本惩罚,比如客户希望上午收货但下午也行,晚到一个小时罚多少钱。

这个清单做完,模型才算真正对接了业务。算法不会读空气,你不把约束说透,它就会给你一份“纸上最优”的路线表。

5.3 距离数据的坑

方案的绝对数字能不能被业务认可,经常卡在距离计算上。如果你用欧氏直线距离代替实际路网距离,总里程会明显偏低,司机一看就知道对不上油表。解决办法很简单:用地图服务的路线距离矩阵API,把仓库和客户之间的实际开车距离提前算好,存成一张离线查表矩阵,运行时直接读缓存,避免每次求解都调API。

另外一个隐性坑是坐标漂移。有些客户地址的门牌坐标和真实收货点还差上百米,算法看着准,实际跑起来可能绕路。所以要做两件事:第一,对高频配送点做坐标人工校准;第二,距离矩阵计算前,把“客户坐标”和“可停靠点坐标”区分开。这个细节对最后上线效果影响很大。

5.4 动态订单怎么办

很多团队做完静态MDVRP系统,上线后发现现实根本不是静态的——十点半又有新订单进来,客户要加单。静态优化只是起点,不是终点。

我的处理习惯是滚动调度。把今天的时间窗切成若干个批次,比如每半小时一个批次;已经发出去的车锁定路线不再改动,还没出发的订单和新增订单放一起重新计算。这样做既考虑了时效,也不会频繁打乱司机节奏。先用静态模型跑通流程,再在它外面包一层动态重算逻辑,是落地最稳的路径。

这层逻辑不复杂,但价值很大。很多所谓“上了系统反而更乱”的抱怨,根源就在于系统把所有订单绑死在一个静态方案里,对新增需求缺少重新计算机制。

5.5 常见问题速查表

症状可能原因处理方式
优化后总里程比人工排线还高用了直线距离,或边界客户归属错误换路网距离矩阵;检查归属与仓覆盖逻辑
求解器报无可行解硬约束太多,或车辆数、容量设置不合理减少硬约束、加软惩罚;检查容量是否足够
车辆装载率极低但里程不低目标函数只考虑了里程,没考虑台数成本目标函数加入固定车辆启动成本
司机反馈某个片区路不好走路线使用了瞬时最优,没考虑实际路况引入路况时间系数,或调整该片区惩罚权重
系统每轮计算超过10分钟模型太大,或时间窗太硬切分调度批次;软时间窗;限制搜索时间

做完模拟项目X,我最大的体会是多配送中心车辆路径优化的难点不完全在算法。把“什么算好”和业务对齐,往往决定这套东西能不能真正用起来。算法方案被采纳,靠的不是数学证明,而是你要能把它变成一张调度员看得懂的地图,以及一套可以解释为什么这么排的规则。我后来做新的仓配项目时,习惯先把OR-Tools跑出的基线解打印出来跟调度负责人一起看,让她在合理性上挑刺,再针对她指出的位置调整软约束权重,上线阻力一下就小了很多。

最后分享一个小建议:不要急着上系统,先做离线回放。拿两个月的历史订单跑一遍模拟,对比真实发生过的里程和车次,把优化率算出来,再拿给决策层看。数据不会骗人,也比一堆技术名词有说服力。这个内容后续还能扩展成带实时插单、动态重排、新能源车充电约束的完整调度系统,但底座都是同一个:多配送中心的整体协同优化。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询