
本文详解如何突破标准车辆路径问题(vrp)限制,在 optaplanner 中灵活建模医院担架员调度场景:支持单任务多人员协同、无需地理坐标、仅依赖时间窗约束,并提供可落地的领域模型设计与约束编码方案。
本文详解如何突破标准车辆路径问题(vrp)限制,在 optaplanner 中灵活建模医院担架员调度场景:支持单任务多人员协同、无需地理坐标、仅依赖时间窗约束,并提供可落地的领域模型设计与约束编码方案。
OptaPlanner 本身并非绑定于传统 VRP 的几何假设(如经纬度、欧氏距离),而是一个通用的约束优化引擎。所谓“必须提供坐标”“只能单车服务单客户”,实为官方 VRP 示例(vehicle-routing) 的实现选择,而非框架能力边界。针对担架员调度这一典型医疗资源协同场景,我们可通过重构领域模型与定制硬/软约束,完全适配实际业务需求。
✅ 正确建模关键点
将 Vehicle 映射为 StretcherBearer(担架员)
每位担架员是独立可调度资源,具备工作时段、技能资质(如是否持证搬运重症患者)等属性。-
将 Customer 升级为 Mission(任务),并支持多担架员协同
不再强制“1 Mission → 1 StretcherBearer”,而是定义 Mission 类含 requiredBearerCount: int 字段(如转运手术患者需 requiredBearerCount = 2)。@PlanningEntity public class Mission { private Long id; private int requiredBearerCount; // 例如:1 或 2 private LocalDateTime arrivalWindowStart; private LocalDateTime arrivalWindowEnd; private Duration serviceDuration; // 搬运+交接耗时 // ... getter/setter } -
移除地理坐标,用时间驱动行程逻辑
若仅有各任务的最早/最晚到达时间(arrival/departure time windows)及任务间转移耗时(非距离,而是预估的移动+准备时间),可直接建模为 TimeWindowedTask 关系:- 在 StretcherBearer 实体中维护其当前 currentEndTime;
- 约束 mission.startDateTime ≥ currentEndTime + transferDurationBetween(mission.previous, mission);
- transferDurationBetween 可从医院内部路由表查得(如“A病区→B手术室=8分钟”),以 Map 或数据库加载,无需坐标计算。
⚙️ 核心约束示例(DRL 或 ConstraintStream)
// ConstraintStream 方式:确保任务获得足额担架员
Constraint sufficientBearersForMission(ConstraintFactory factory) {
return factory.from(Mission.class)
.filter(mission -> mission.getRequiredBearerCount() > 0)
.join(StretcherBearer.class,
Joiners.equal(Mission::getId, StretcherBearer::getAssignedMissionId))
.groupBy((mission, bearer) -> mission,
(mission, bearer) -> Collectors.counting())
.filter((mission, assignedCount) -> assignedCount
mission.getRequiredBearerCount() - assignedCount);
}
? 提示:若某任务需 2 人但仅分配 1 人,扣 1 分硬约束;0 人则扣 2 分——实现阶梯式惩罚,引导求解器优先满足关键任务。
? 数据输入:JSON / .vrptw 文件适配建议
OptaPlanner 不强制要求 .vrptw 格式。推荐使用 自定义 JSON Schema,清晰表达医疗调度语义:
{
"stretcherBearers": [
{ "id": 1, "availableFrom": "08:00", "availableTo": "17:00", "skills": ["basic"] },
{ "id": 2, "availableFrom": "09:00", "availableTo": "18:00", "skills": ["icu", "basic"] }
],
"missions": [
{
"id": 101,
"requiredBearerCount": 2,
"arrivalWindow": { "start": "09:30", "end": "10:00" },
"serviceDurationMinutes": 15,
"locationCode": "ICU-3F"
}
],
"transferDurations": {
"ICU-3F→OR-2F": 8,
"OR-2F→Ward-4E": 6
}
}
通过 JsonSolverFactory 加载该结构,配合自定义 Solution 类(含 List
? 注意事项与最佳实践
- 避免强行套用 VRP 示例代码:删除所有 DistanceMatrix、GeoLocation 相关逻辑,聚焦时间窗与资源协同;
-
转移时间需业务校准:联合后勤部门实测各病区间通行时间,构建静态 Map
表,比坐标推算更准确可靠; - 区分硬/软约束层级:人员数量不足、超时服务设为硬约束;早到等待、总工时均衡设为软约束;
- 验证输出合理性:检查解中是否存在同一担架员被分配至时间冲突的两个任务,或任务未达最低人力要求。
综上,OptaPlanner 完全胜任担架员多角色协同调度——关键在于跳出“VRP 即必须带坐标的送货问题”的思维定式,回归优化本质:定义好实体、关系与业务规则,框架自会寻找最优分配方案。











