使用OR-Tools CP-SAT最小化司机总数的约束问题排查
问题:OR-Tools SAT求解器司机排班约束错误,多班次场景结果异常
核心需求
- 目标:最小化司机数量
- 约束条件:
- 每个班次必须分配给至少一名司机
- 同一司机同一时间只能承接一个班次(无时间重叠)
- 司机承接的连续班次需满足:前一班结束时间 ≤ 下一班开始时间
现有问题
3-4个班次时调整约束后结果正确,但5-6个班次时结果不符合预期或显示不可行,怀疑约束语句model.Add((1 - tasks_assignment[driver, task]) >= tasks_assignment[driver,task2]).OnlyEnforceIf(task_overlap[driver, task])存在逻辑错误。
问题分析
- 约束逻辑完全反转:你的
task_overlap定义是「0=班次无法连续承接,1=可连续承接」,但原约束的逻辑是:当task_overlap[driver,task]为真(可连续)时,强制1 - tasks_assignment[driver,task] >= tasks_assignment[driver,task2]——也就是如果司机接了task,就不能接task2,这和你想要的连续承接逻辑完全相反。 - 兼容性矩阵维度错误:班次能否连续承接是由时间决定的,和司机无关,
task_overlap应该是二维矩阵task_overlap[task1, task2],而非绑定司机的三维矩阵。
正确解决方案
1. 预生成班次兼容性矩阵
先基于班次时间生成can_assign_together二维矩阵,明确哪些班次对可以分配给同一司机:
num_tasks = 6 # 假设tasks是存储班次信息的列表,每个元素格式为[..., start_time, end_time] can_assign_together = [[0]*num_tasks for _ in range(num_tasks)] for task1 in range(num_tasks): for task2 in range(num_tasks): if task1 != task2: # 判断task1结束时间 ≤ task2开始时间(确保可连续承接) if tasks[task1][4] <= tasks[task2][3]: can_assign_together[task1][task2] = 1 else: can_assign_together[task1][task2] = 0
2. 修正同一司机的班次约束
对所有不兼容的班次对,约束同一司机不能同时承接:
for driver in range(num_drivers): for task1 in range(num_tasks): for task2 in range(task1+1, num_tasks): # 如果两个班次既不能连续承接,也不能同时承接(时间重叠) if can_assign_together[task1][task2] == 0 and can_assign_together[task2][task1] == 0: model.Add(tasks_assignment[driver, task1] + tasks_assignment[driver, task2] <= 1)
3. 补充必要约束与目标函数
- 确保每个班次都被分配:
for task in range(num_tasks): model.Add(sum(tasks_assignment[driver, task] for driver in range(num_drivers)) == 1)
- 定义司机使用状态,最小化司机数量:
driver_used = [model.NewBoolVar(f'driver_used_{d}') for d in range(num_drivers)] for driver in range(num_drivers): # 司机有排班则标记为已使用 model.Add(sum(tasks_assignment[driver, task] for task in range(num_tasks)) >= 1).OnlyEnforceIf(driver_used[driver]) # 司机无排班则标记为未使用 model.Add(sum(tasks_assignment[driver, task] for task in range(num_tasks)) == 0).OnlyEnforceIf(driver_used[driver].Not()) # 目标:最小化使用的司机总数 model.Minimize(sum(driver_used))
原约束仅部分场景生效的原因
原约束逻辑反转,且错误绑定司机与班次兼容性,小数量班次时解空间小,偶然避开了冲突;但班次数量增加后,错误约束会排除大量可行解,或允许不符合时间要求的排班,导致结果异常。
内容的提问来源于stack exchange,提问作者D5015
相关产品推荐
相关产品推荐

