护士排班建模:滑动6周窗口内至少14天连续无班次约束实现方法
基于OR-Tools CP-SAT求解器的约束建模方案
你需要新增辅助布尔变量配合滑动窗口逻辑实现该约束,具体步骤如下:
- 预定义常量
首先明确三个基础常量,和你现有排班逻辑的编码规则保持一致:
OFF_SHIFT:代表无排班的O班次对应的编码值WINDOW_LENGTH:滑动窗口长度,6周对应42天REQUIRED_OFF_DAYS:要求的连续休息天数,即14天
- 新增辅助布尔变量
为每位护士n、每个可能的连续14天休息起始日期s,定义布尔变量has_14d_off_start_at[n][s]:
- 变量值为
True时,代表护士n从第s天到第s+13天(共14天)全为O班次 - 变量取值覆盖所有合法的
s:即`s + REQUIRED_OFF_DAYS - 1 < 总排班天数
- 绑定辅助变量和排班变量
对每个护士n、每个合法的起始日期s,添加两组约束:
# 约束1:如果has_14d_off_start_at[n][s]为真,对应14天必须全是休息 model.AddBoolAnd([ shifts[n][d] == OFF_SHIFT for d in range(s, s + REQUIRED_OFF_DAYS) ]).OnlyEnforceIf(has_14d_off_start_at[n][s]) # 约束2:如果对应14天中存在任意一天不是休息,has_14d_off_start_at[n][s]必须为假 for d in range(s, s + REQUIRED_OFF_DAYS): model.AddImplication( shifts[n][d] != OFF_SHIFT, has_14d_off_start_at[n][s].Not() )
- 添加滑动窗口规则约束
对每个护士n、每个滑动窗口的起始日期w(窗口覆盖第w天到第w + WINDOW_LENGTH - 1天),要求该窗口内至少存在一个合法的14天连续休息段:
# 每个滑动窗口内合法的连续休息起始日期范围是[w, w + WINDOW_LENGTH - REQUIRED_OFF_DAYS] valid_starts = [s for s in range(w, w + WINDOW_LENGTH - REQUIRED_OFF_DAYS + 1)] # 要求至少有一个起始日期对应的14天休息变量为真 model.AddBoolOr([has_14d_off_start_at[n][s] for s in valid_starts])
方案说明
该实现完全匹配你的需求:仅要求每个滑动6周窗口内至少存在一段14天连续休息,不会限制其他非目标休息段的长度,也不会强制所有休息段都满足14天要求,完美避开了add_soft_sequence_constraint的适配问题。
如果需要将该约束设为软约束,只需要给每个滑动窗口新增一个惩罚布尔变量,当窗口不满足约束时触发惩罚,将惩罚值计入目标函数即可。
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

