最近研究了一个多仓库、多车辆、多客户的车辆路径优化问题(Vehicle Routing Problem, VRP),通过数学建模与求解器优化,在满足约束条件的前提下,最小化总行驶距离,提升物流配送效率。可以在这个子问题的基础上,扩展延伸到更复杂的模型。
✅ 主要特点
-
支持多仓库、多车辆、多客户:模型允许多个仓库同时运作,车辆可从各自仓库出发,为多个客户服务;
-
客户可被多车联合服务:引入分配变量
z[v, c],允许一个客户的需求由多辆车联合配送; -
车辆路径变量
y[v, i, j]:表示车辆v是否从节点i行驶到节点j; -
支持子环消除(MTZ约束):使用
u[v, i]变量消除非法子环; -
考虑车辆载重与行驶距离约束:每辆车在服务过程中不得超载或超过最大运行里程;
-
可视化方案输出:结合
matplotlib,展示车辆路径图、仓库和客户分布及服务关系。
🛠 使用工具
-
建模与求解器:
使用 Gurobi Optimizer 建立混合整数规划(MIP)模型,处理复杂的路径规划与资源约束问题; -
编程语言:
Python 3,使用gurobipy接口进行建模; -
数据可视化:
利用matplotlib实现客户、仓库与车辆路径的空间布局图,辅助结果分析。
✅ 适用场景
本模型可用于如下物流/调度场景的决策优化:
-
城市配送中涉及多个分拨仓的路径优化;
-
冷链配送、医疗物资运输等车辆容量和时效要求较强的情形;
-
快递末端配送中需多车协同完成客户需求分发的场景。
✅ 可运行代码和结果图
结果图:


部分核心代码如下:
class OptimizedVehicleRoutingProblem:
def __init__(self, simplify_model=True, time_limit=300, mip_gap=0.05):
self.warehouses = []
self.customers = []
self.vehicles = []
self.distance_matrix = None
self.model = None
self.simplify_model = simplify_model
self.time_limit = time_limit
self.mip_gap = mip_gap
def add_warehouse(self, id, x, y, capacity):
self.warehouses.append({'id': id, 'x': x, 'y': y, 'capacity': capacity})
def add_customer(self, id, x, y, demand):
self.customers.append({'id': id, 'x': x, 'y': y, 'demand': demand})
def add_vehicle(self, id, warehouse_id, capacity, range_limit):
self.vehicles.append({'id': id, 'warehouse_id': warehouse_id, 'capacity': capacity, 'range_limit': range_limit})
def calculate_distance_matrix(self):
all_points = self.warehouses + self.customers
n = len(all_points)
self.distance_matrix = np.zeros((n, n))
for i in range(n):
for j in range(n):
if i != j:
dx = all_points[i]['x'] - all_points[j]['x']
dy = all_points[i]['y'] - all_points[j]['y']
self.distance_matrix[i][j] = math.sqrt(dx * dx + dy * dy)
def build_model(self):
self.calculate_distance_matrix()
self.model = gp.Model("OptimizedVRP")
self.model.setParam('TimeLimit', self.time_limit)
self.model.setParam('MIPGap', self.mip_gap)
self.model.setParam('OutputFlag', 1)
W = range(len(self.warehouses))
C = range(len(self.customers))
V = range(len(self.vehicles))
N = range(len(self.warehouses) + len(self.customers))
if self.simplify_model:
y = self.model.addVars(V, N, N, vtype=GRB.BINARY, name="vehicle_route")
z = self.model.addVars(V, C, vtype=GRB.CONTINUOUS, lb=0, ub=1, name="vehicle_visit")
u = self.model.addVars(V, N, vtype=GRB.CONTINUOUS, lb=0, ub=len(N) - 1, name="visit_order")
self.y, self.z, self.u = y, z, u
else:
raise NotImplementedError("Only simplify_model=True is currently supported.")
self.model.setObjective(gp.quicksum(self.distance_matrix[i][j] * y[v, i, j] for v in V for i in N for j in N if i != j), GRB.MINIMIZE)
for v in V:
warehouse_idx = self.vehicles[v]['warehouse_id']
self.model.addConstr(gp.quicksum(y[v, warehouse_idx, j] for j in N if j != warehouse_idx) == 1)
self.model.addConstr(gp.quicksum(y[v, i, warehouse_idx] for i in N if i != warehouse_idx) == 1)
for i in N:
if i != warehouse_idx:
self.model.addConstr(gp.quicksum(y[v, i, j] for j in N if j != i) == gp.quicksum(y[v, j, i] for j in N if j != i))
self.model.addConstr(gp.quicksum(self.customers[c]['demand'] * z[v, c] for c in C) <= self.vehicles[v]['capacity'])
self.model.addConstr(gp.quicksum(self.distance_matrix[i][j] * y[v, i, j] for i in N for j in N if i != j) <= self.vehicles[v]['range_limit'])
for c in C:
customer_idx = len(self.warehouses) + c
self.model.addConstr(z[v, c] <= gp.quicksum(y[v, i, customer_idx] for i in N if i != customer_idx))
for c in C:
self.model.addConstr(gp.quicksum(z[v, c] * self.customers[c]['demand'] for v in V) >= self.customers[c]['demand'])
for v in V:
warehouse_idx = self.vehicles[v]['warehouse_id']
self.model.addConstr(self.u[v, warehouse_idx] == 0)
for i in N:
for j in N:
if i != j and i != warehouse_idx and j != warehouse_idx:
self.model.addConstr(self.u[v, i] - self.u[v, j] + (len(N) - 1) * y[v, i, j] <= len(N) - 2)
1085

被折叠的 条评论
为什么被折叠?



