如何适配OptaPlanner实现担架员巡诊任务的车辆路径优化
适配OptaPlanner解决担架员巡诊任务的方案
针对你提到的两个核心问题,完全可以通过定制OptaPlanner的约束和数据模型来适配业务场景,以下是具体解决方案:
问题1:部分任务需要2名担架员(双Vehicle需求)
OptaPlanner原生VRP组件不直接支持多车辆协同任务,但可以通过两种方式实现:
关联子任务约束法
将需要2名担架员的任务拆分为两个绑定的子任务,每个子任务对应一名担架员的工作项。在OptaPlanner中添加硬约束:- 这两个子任务必须分配给不同的担架员(Vehicle实例);
- 两个子任务的时间窗口(到达/离开时间)必须完全重叠;
- 分配子任务的担架员在该时间窗口内不能承接其他任务。
可以通过自定义ConstraintProvider实现这些规则,确保双人任务的协同要求。
担架员组资源模型
扩展Vehicle模型为StretcherTeam(担架员组),添加teamSize字段(1或2)。任务分为SinglePersonTask和DoublePersonTask,在约束中限制:DoublePersonTask只能分配给teamSize=2的组;SinglePersonTask可分配给任意组。
这种方式把问题转化为带资源能力约束的VRP,更贴合实际业务的资源组织逻辑。
问题2:无坐标仅含时间数据的适配
OptaPlanner的VRP默认依赖坐标计算距离,但可以通过两种方式绕过坐标要求:
时间差替代距离计算
不需要坐标,直接基于任务的时间属性定义"行驶时间"。自定义实现DistanceCalculator接口,在计算两个任务之间的距离时,返回它们的时间窗口间隔(比如任务A的离开时间到任务B的到达时间的差值,若为负则取0)。这样OptaPlanner的路径规划会基于任务的时间衔接逻辑进行,完全符合医院巡诊的实际调度需求。生成虚拟一维坐标
如果必须保留坐标字段以兼容OptaPlanner的默认组件,可以将时间映射为一维坐标:- 收集所有任务的到达时间,按顺序排序;
- 将每个任务的x坐标设为其到达时间的数值(如9点设为900,9点半设为930),y坐标固定为0;
- 两个任务之间的欧氏距离自然等于时间差,满足OptaPlanner的距离计算要求,同时不影响时间窗口约束。
生成适配的JSON或.vrptw文件
JSON格式示例
按照OptaPlanner VRP的数据结构定义,扩展字段以支持双人任务和时间属性:
{ "stretcherTeams": [ {"id": "T001", "teamSize": 1}, {"id": "T002", "teamSize": 1}, {"id": "T003", "teamSize": 2} ], "tasks": [ {"id": "TS001", "taskType": "SINGLE", "arrivalTime": 900, "departureTime": 930}, {"id": "TD001-1", "taskType": "DOUBLE", "sharedTaskId": "TD001", "arrivalTime": 915, "departureTime": 945}, {"id": "TD001-2", "taskType": "DOUBLE", "sharedTaskId": "TD001", "arrivalTime": 915, "departureTime": 945} ] }
.vrptw格式示例
扩展标准VRPTW字段,添加自定义属性(如团队容量、共享任务ID),并使用虚拟时间坐标:
NAME: HospitalStretcherVRPTW COMMENT: Stretcher routing with double-person tasks TYPE: VRPTW DIMENSION: 5 VEHICLES: 3 CAPACITY: [1,1,2] EDGE_WEIGHT_TYPE: EUC_2D NODE_COORD_SECTION 1 0 0 # 起点 2 900 0 # 单人任务1 3 915 0 # 双人任务子项1 4 915 0 # 双人任务子项2 5 945 0 # 单人任务2 DEMAND_SECTION 1 0 2 1 3 1 4 1 5 1 TIME_WINDOW_SECTION 1 0 1440 2 900 930 3 915 945 4 915 945 5 945 975 SHARED_TASK_SECTION # 自定义扩展段 3 4 # 标记任务3和4属于同一共享任务 DEPOT_SECTION 1 -1
内容的提问来源于stack exchange,提问作者Amine El Harchaoui
相关产品推荐
相关产品推荐

