如何在OR-Tools多品类容量场景下添加危化品非半载路由约束
危化品运输路由:禁止半载的OR-Tools约束实现
需求明确
危化品液体运输要求车辆不能半载行驶——即车辆从仓库(depot)出发后,访问的第一个需求节点必须将对应品类的货物全部卸下,卸完后车辆处于空(或近乎空,允许极小残留可调整阈值)状态。
代码实现步骤
第一步:保存各品类的容量维度对象
原有循环仅实现了基础容量约束,现在需要把每个品类的维度对象存储下来,方便后续添加定制约束:
# 新增:存储每个品类的容量维度,用于后续约束配置 capacity_dims = {} def demand_callback(type): def callback(from_index): from_node = manager.IndexToNode(from_index) return data["demands_by_types"][type][from_node] return callback for type in range(len(data["demands_by_types"])): dim_name = f'Capacity_type_{type}' routing.AddDimensionWithVehicleCapacity( routing.RegisterUnaryTransitCallback(demand_callback(type)), 0, # 无容量松弛空间 data["capacities_by_type"][type], # 车辆对应品类的最大装载容量 True, # 初始累积装载量为0 dim_name ) # 保存当前品类的维度对象 capacity_dims[type] = routing.GetDimensionOrDie(dim_name)
第二步:添加禁止半载的定制约束
遍历每辆车,约束其第一个访问节点的需求等于车辆初始装载量,且到达该节点后对应品类的剩余装载量为0:
# 遍历所有车辆 for vehicle_id in range(data["num_vehicles"]): # 获取车辆出发的仓库节点索引 depot_idx = manager.NodeToIndex(data["depot"]) # 获取车辆从仓库出发后第一个访问节点的变量 first_node_var = routing.NextVar(depot_idx) # 逐个品类添加约束 for type in range(len(data["demands_by_types"])): dim = capacity_dims[type] # 仓库处的累积量 = 车辆初始装载的该品类货物量 depot_cumul = dim.CumulVar(depot_idx) # 第一个节点处的累积量 = 卸完货后的剩余量 first_node_cumul = dim.CumulVar(first_node_var) # 约束1:初始装载量等于第一个节点的该品类需求 routing.solver().Add( depot_cumul == data["demands_by_types"][type][manager.IndexToNode(first_node_var)] ) # 约束2:到达第一个节点后,该品类货物全部卸空,剩余量为0 routing.solver().Add(first_node_cumul == 0) # 若业务允许极小残留(如≤0.0001),可替换为: # routing.solver().Add(first_node_cumul <= 1e-4)
特殊情况说明
- 若车辆仅往返仓库(无需求节点):无需约束,因无装载行为
- 多品类混装场景:每个品类单独约束,确保所有品类均满足“第一个节点卸空”要求
内容的提问来源于stack exchange,提问作者maxvelichko26
相关产品推荐
相关产品推荐

