基于OR-Tools的护士排班休息日约束添加技术问询
Google OR-Tools 护士排班休息日约束实现方案
针对你的需求,下面提供两种直观的实现方式,均基于你的shift[n,d,s]布尔变量(shift[n,d,s]=1表示护士n在第d天第s班次被安排):
方法一:直接强制休息日班次为0(推荐新手)
这是最直观的方式,直接约束护士在休息日当天的所有班次变量必须为0:
from ortools.sat.python import cp_model # 基础参数 num_nurses = 4 num_days = 3 # 匹配休息日的0/1/2索引 num_shifts = 3 # 根据实际班次数调整 nurse_days_off = [ [0,2], [1], [1,2], [] ] # 初始化模型与变量 model = cp_model.CpModel() shift = {} for n in range(num_nurses): for d in range(num_days): for s in range(num_shifts): shift[(n, d, s)] = model.NewBoolVar(f'shift_n{n}_d{d}_s{s}') # 原有约束:每个班次仅分配一名护士 for d in range(num_days): for s in range(num_shifts): model.AddExactlyOne(shift[(n, d, s)] for n in range(num_nurses)) # 添加休息日约束 for nurse_idx in range(num_nurses): # 遍历该护士的所有休息日 for day_off in nurse_days_off[nurse_idx]: # 该休息日的所有班次都禁止安排 for shift_idx in range(num_shifts): model.Add(shift[(nurse_idx, day_off, shift_idx)] == 0)
方法二:使用AddForbiddenAssignments
如果你一定要用AddForbiddenAssignments,需明确:该方法第一个参数是变量列表,第二个参数是禁止的取值元组列表(元组长度必须和变量列表长度一致)。对于单个班次变量,我们禁止它取1这个值:
# 替换方法一中的休息日约束部分,其余代码不变 for nurse_idx in range(num_nurses): for day_off in nurse_days_off[nurse_idx]: for shift_idx in range(num_shifts): target_var = shift[(nurse_idx, day_off, shift_idx)] # 禁止该变量被设为1 model.AddForbiddenAssignments([target_var], [(1,)])
关键说明
- 两种方法效果完全一致,但方法一可读性更强,更适合约束编程新手理解。
- 确保
num_days的取值覆盖你nurse_days_off中的所有日期索引(比如示例中用到0/1/2,所以num_days设为3)。
内容的提问来源于stack exchange,提问作者Mark Seagoe
相关产品推荐
相关产品推荐

