You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google OR-Tools中OnlyEnforceIf设置排班约束不生效问题求助

问题原因

你写的约束没生效,基本是踩了两个OR-Tools排班的常见坑,和OnlyEnforceIf本身语法无关:

  • 最常见的是硬编码班次索引导致映射错位:你代码里直接写了4、1、2三个班次号,但从注释看你自己对班次的标记(N/O/M)和需求里的A/B/C班没有做明确对应,本质是约束绑错了要控制的变量。
  • 其次是缺基础约束或边界写错:如果没加「每个员工每天只能值一个班次」的硬约束,会出现同一员工同一天多个班次BoolVar同时为1的情况,导致触发条件判断失效;另外如果你的天索引起始规则不统一(比如一会从0算一会从1算),要么会漏判要么会越界。
正确写法

先确保两个前提:

  • 提前定义班次常量,绝对不要在约束里硬编码数字,比如:
    A_SHIFT = 0  # 规则里第1天要值的A班
    B_SHIFT = 1  # 规则里第2天要值的B班
    C_SHIFT = 2  # 规则里第3天禁止值的C班
    
  • 补上单日单班的硬约束(之前没加的话必须补,不然所有排班规则都可能乱):
    for e in range(num_employees):
        for d in range(num_days):
            # 每个员工每天必须且仅能选一个班次(含休息班)
            model.AddExactlyOne(work[e, s, d] for s in range(num_shifts))
    

之后选任意一种写法实现连班限制即可:

写法1:修正后的OnlyEnforceIf(天索引从0开始,即第一天d=0)

for e in range(num_employees):
    # d最大取到num_days-3,保证d+2不会超出最后一天的索引
    for d in range(num_days - 2):
        cond_day1 = work[e, A_SHIFT, d]
        cond_day2 = work[e, B_SHIFT, d+1]
        ban_day3 = work[e, C_SHIFT, d+2]
        # 两个触发条件同时为真时,强制第3天C班为0
        model.Add(ban_day3 == 0).OnlyEnforceIf(cond_day1, cond_day2)

写法2:禁止赋值写法(更不容易出错,推荐)

不用记OnlyEnforceIf的触发逻辑,直接把三个变量的非法组合列出来,求解器会自动规避,逻辑和需求完全等价:

for e in range(num_employees):
    for d in range(num_days - 2):
        v1 = work[e, A_SHIFT, d]
        v2 = work[e, B_SHIFT, d+1]
        v3 = work[e, C_SHIFT, d+2]
        # 明确禁止「v1=1、v2=1、v3=1」的组合
        model.AddForbiddenAssignments([v1, v2, v3], [(1, 1, 1)])
排查清单

改完还是不符合预期的话,按顺序查:

  • 确认work的维度顺序是[员工ID, 班次ID, 日期ID],没有把班次和日期的维度写反
  • 确认班次ID的范围和你初始化work时的班次总数一致,不存在索引越界
  • OnlyEnforceIf里只能传BoolVar本身,不要传类似work[e,A_SHIFT,d] == 1的布尔表达式,需要判断变量为假的场景用model.Not(对应BoolVar)包裹

内容的提问来源于stack exchange,提问作者Carson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:57:22