Python+Gurobi 线性规划排班实战:14人20时段约束下的最优解

发布时间:2026/7/10 7:47:00
Python+Gurobi 线性规划排班实战:14人20时段约束下的最优解 PythonGurobi 线性规划排班实战14人20时段约束下的最优解当14位团队成员需要覆盖20个不同时段的服务需求时如何设计公平高效的排班方案传统手工排班不仅耗时费力还难以兼顾多重约束条件。本文将展示如何用数学建模将复杂业务规则转化为精确的线性规划问题并通过PythonGurobi实现自动化排班决策。1. 排班问题的数学建模排班问题本质上是在满足业务需求和员工权益之间寻找平衡点。我们需要将以下业务规则转化为数学表达式时段覆盖要求每个时段需要至少指定数量的员工在岗员工可用性每位员工只能在特定时段工作公平性约束尽量均衡各员工的工作时段数量特殊规则如连续工作时长限制、技能匹配等1.1 决策变量定义采用二进制变量表示排班决策# 创建二进制决策变量 x model.addVars(employees, time_slots, vtypeGRB.BINARY, namex)其中employees: 员工集合14人time_slots: 时段集合20个x[r,t]: 员工r在时段t是否工作1工作0休息1.2 目标函数设计为平衡工作负荷我们最小化最大与最小工作时段数的差值# 辅助变量最大/最小工作时段数 max_work model.addVar(namemax_work) min_work model.addVar(namemin_work) # 目标函数最小化工作负荷差异 model.setObjective(max_work - min_work, GRB.MINIMIZE)1.3 约束条件构建时段覆盖约束确保每个时段有足够人手# 每个时段至少需要required[t]名员工 model.addConstrs( (x.sum(*, t) required[t] for t in time_slots), namecoverage )员工可用性约束尊重个人时间安排# 员工r只能在available[r,t]1的时段工作 model.addConstrs( (x[r,t] available[r,t] for r in employees for t in time_slots), nameavailability )工作负荷约束控制公平性# 计算每位员工总工作时段数 total_work {r: x.sum(r, *) for r in employees} # 设置max_work/min_work与各员工工作量的关系 model.addConstrs( (total_work[r] max_work for r in employees), namemax_def ) model.addConstrs( (total_work[r] min_work for r in employees), namemin_def )2. PythonGurobi完整实现2.1 数据准备与模型初始化import gurobipy as gp from gurobipy import GRB import pandas as pd # 初始化模型 model gp.Model(Staff_Scheduling) # 示例数据14名员工20个时段 employees [fE{i} for i in range(1, 15)] time_slots [fT{i} for i in range(1, 21)] # 随机生成可用性矩阵实际应用应从文件读取 import numpy as np np.random.seed(42) available pd.DataFrame( np.random.choice([0, 1], size(14, 20), p[0.3, 0.7]), indexemployees, columnstime_slots ) # 时段需求随机生成2-4人 required {t: np.random.randint(2, 5) for t in time_slots}2.2 模型构建与求解# 创建决策变量 x model.addVars(employees, time_slots, vtypeGRB.BINARY, namex) # 创建辅助变量 max_work model.addVar(namemax_work) min_work model.addVar(namemin_work) # 设置目标函数 model.setObjective(max_work - min_work, GRB.MINIMIZE) # 添加约束条件 model.addConstrs( (x.sum(*, t) required[t] for t in time_slots), namecoverage ) model.addConstrs( (x[r,t] available.loc[r,t] for r in employees for t in time_slots), nameavailability ) total_work {r: x.sum(r, *) for r in employees} model.addConstrs( (total_work[r] max_work for r in employees), namemax_def ) model.addConstrs( (total_work[r] min_work for r in employees), namemin_def ) # 求解模型 model.optimize()2.3 结果分析与可视化# 检查求解状态 if model.status GRB.OPTIMAL: print(f最优解找到目标值{model.objVal:.2f}) # 提取排班结果 schedule pd.DataFrame( [[round(x[r,t].x) for t in time_slots] for r in employees], indexemployees, columnstime_slots ) # 计算各员工工作时段数 work_counts schedule.sum(axis1) print(\n各员工工作时段数统计) print(work_counts.describe()) # 可视化排班表 import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) plt.imshow(schedule, cmapBlues) plt.xlabel(Time Slots) plt.ylabel(Employees) plt.title(Optimal Staff Schedule) plt.colorbar(labelWorking (1) / Off (0)) plt.show() else: print(未找到可行解)3. 模型优化与扩展3.1 添加复杂业务规则实际排班通常需要更多约束条件连续工作限制# 禁止连续工作超过4个时段 for r in employees: for t in range(len(time_slots)-4): model.addConstr( x[r,time_slots[t]] x[r,time_slots[t1]] x[r,time_slots[t2]] x[r,time_slots[t3]] 4, namefmax_consecutive_{r}_{t} )技能匹配要求# 假设某些时段需要特定技能 skill_required {T3: A, T8: B, T15: C} employee_skills {E1: [A,B], E2: [B,C], ...} # 实际应完整定义 for t, skill in skill_required.items(): model.addConstr( gp.quicksum(x[r,t] for r in employees if skill in employee_skills[r]) 1, namefskill_{t} )3.2 多目标优化平衡多个优化目标时可以使用Gurobi的多目标功能# 第一目标最小化最大工作差异 model.setObjectiveN(max_work - min_work, index0, priority2, namefairness) # 第二目标最小化总人力成本假设不同员工成本不同 cost {r: np.random.uniform(1.0, 1.5) for r in employees} # 随机生成成本系数 total_cost gp.quicksum(x[r,t]*cost[r] for r in employees for t in time_slots) model.setObjectiveN(total_cost, index1, priority1, namecost)3.3 大规模问题处理技巧当员工和时段数量增加时可采用以下策略延迟变量创建仅在实际需要时添加变量约束懒惰更新使用model.update()控制约束添加频率并行求解设置Threads参数利用多核CPU启发式策略先用简单规则生成初始解# 优化参数设置 model.Params.Threads 4 # 使用4个线程 model.Params.MIPGap 0.01 # 允许1%的优化间隙 model.Params.TimeLimit 300 # 5分钟时间限制4. 实际应用建议4.1 数据预处理最佳实践使用Pandas处理原始排班数据建立数据验证流程检查一致性为特殊日期节假日创建例外规则# 示例从Excel读取可用性数据 availability_df pd.read_excel(availability.xlsx, index_col0) # 验证数据完整性 assert set(availability_df.index) set(employees), 员工列表不匹配 assert set(availability_df.columns) set(time_slots), 时段列表不匹配4.2 模型调试技巧当模型无可行解时检查约束冲突使用model.computeIIS()找出不可行约束逐步放松约束识别最严格的限制条件可视化冲突标记导致问题的员工/时段组合# 分析不可行模型 if model.status GRB.INFEASIBLE: print(模型不可行正在分析冲突...) model.computeIIS() model.write(model.ilp) # 导出不可行子系统 print(冲突分析已保存到model.ilp)4.3 结果后处理生成易于理解的排班表# 创建人性化的排班报告 def generate_schedule_report(schedule_df): report [] for t in time_slots: working schedule_df.index[schedule_df[t] 0.5].tolist() report.append(f{t}: {, .join(working)}) return \n.join(report) print(generate_schedule_report(schedule))通过这种方法我们成功将复杂的排班问题转化为可计算的数学模型在满足多种业务约束的同时实现了工作负荷的公平分配。该框架可根据具体需求灵活调整适用于各种资源调度场景。