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

如何用Pulp在Python中正确设置排班约束解决不可行错误?

排班工具Pulp约束设置问题及解决方案

问题概述

我尝试用Pulp开发排班工具,核心参数与约束如下:

输入参数

  • 总员工数=8
  • 特殊员工数=4
  • 天数=28
  • 班次=7(对应代码中的day0/day1/day-admit/pm-admit/night0/night1/off)

核心约束

  • 员工每日仅能上一个班次
  • 每日必须填满day0、day1、night0班次
  • 特殊员工在周四(第3、10、17、24天)的夜班/特殊夜班次数不超过2次
  • 每个班次仅安排1人
  • 每位员工必须恰好上5次夜班(night0或night1)
  • 夜班需连续5天安排
  • 员工连续工作天数不超过12天
  • 所有夜班块必须前接1天特殊夜班(pm-admit),后接2天休假(off)

遇到的问题

使用if-else语句设置夜班连续、前后衔接约束时,LP文件未生成预期约束,求解时出现Status Infeasible错误;移除该约束块后可正常求解。


现有代码的核心错误

直接用if var_night0[i][j] == 1这类判断是无效的:

  1. LP变量在建模阶段是符号化的,并非具体数值,if-else会在代码执行时直接运行,无法转化为线性规划约束
  2. 使用break仅处理第一个可能的夜班日,逻辑上无法覆盖所有夜班块的起始情况,导致约束缺失或错误

修正后的约束实现方案

通过辅助二进制变量将逻辑约束转化为线性约束,这是LP建模的标准做法。替换原代码中##### PROBLEM SECTION BELOW #####后的部分为以下代码:

# 处理夜班连续5天、前后衔接的约束
for i in range(number_of_staff):
    start_day_vars = []
    # 遍历所有合法的夜班起始日(确保j+4不超出天数范围)
    for j in range(number_of_days - 4):
        # 辅助变量:标记员工i是否在第j天开始连续5天夜班
        start_shift = pulp.LpVariable(f'start_night_{i}_{j}', cat='Binary')
        start_day_vars.append(start_shift)
        
        # 约束1:如果j是起始日,那么j到j+4这5天必须都是夜班(night0或night1)
        for w in range(5):
            problem += var_night0[i][j+w] + var_night1[i][j+w] >= start_shift
        
        # 约束2:起始日(j>0)前一天必须是特殊夜班(pm-admit)
        if j > 0:
            problem += var_pm_admit[i][j-1] >= start_shift
        
        # 约束3:起始日后两天必须是休假(确保j+6不超出天数范围)
        if j + 6 < number_of_days:
            problem += var_off[i][j+5] >= start_shift
            problem += var_off[i][j+6] >= start_shift
        else:
            # 起始日太晚导致后两天超出排班周期,禁止该起始日
            problem += start_shift == 0
    
    # 约束4:每个员工恰好有一个夜班起始日(保证总夜班数为5天且连续)
    problem += pulp.lpSum(start_day_vars) == 1

# 约束5:确保所有夜班都属于某个连续块(避免零散夜班)
for i in range(number_of_staff):
    for j in range(number_of_days):
        night_shift = var_night0[i][j] + var_night1[i][j]
        # 收集所有可能覆盖j天的夜班起始日
        possible_starts = []
        for s in range(max(0, j-4), min(number_of_days-4, j)+1):
            possible_starts.append(pulp.LpVariable(f'start_night_{i}_{s}', cat='Binary'))
        problem += night_shift <= pulp.lpSum(possible_starts)

代码说明

  1. 辅助变量start_shift:标记每个员工的夜班块起始日,将“连续5天夜班”这类逻辑转化为线性约束
  2. 约束逻辑拆解:
    • 起始日确定后,强制后续4天为夜班
    • 起始日非第一天时,前一天必须是特殊夜班
    • 起始日不能太晚,确保后两天有排班周期可安排休假
    • 每个员工仅能有一个起始日,保证总夜班数为5天
  3. 零散夜班防护:确保所有夜班都属于某个连续块,避免出现单独一天的夜班

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:37:15