基于Gurobi 的多仓库多车辆路径优化模型(含代码)

最近研究了一个多仓库、多车辆、多客户的车辆路径优化问题(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)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值