Google OR-Tools员工排班:如何最小化员工实际分配工时与目标工时偏差
员工排班工时偏差最小化目标函数构造方案
先对齐你提到的两个数组的定义,方便后续代码逻辑匹配:
int[] shiftDurations:长度为numShifts,存储每个班次的时长(单位和目标工时保持一致即可,比如小时)int[] employeeTargetHours:长度为numEmployees,存储每位员工的周目标工时
步骤1:计算每位员工的实际排班总时长
对每个员工遍历所有班次,累加其被分配到的班次的总时长:
IntVar[] actualHours = new IntVar[numEmployees]; for (int e = 0; e < numEmployees; e++) { List<LinearExpr> employeeShifts = new List<LinearExpr>(); for (int s = 0; s < numShifts; s++) { // assign[e,s]为1表示员工e分配到班次s,为0表示未分配 employeeShifts.Add(assign[e, s] * shiftDurations[s]); } // 实际工时范围可根据业务调整,这里设为0到目标工时的2倍足够覆盖常规场景 actualHours[e] = model.NewIntVar(0, employeeTargetHours[e] * 2, $"actual_hours_{e}"); model.Add(LinearExpr.Sum(employeeShifts) == actualHours[e]); }
步骤2:定义偏差变量并添加约束
为了避免正负偏差相互抵消,单独定义低于目标的缺额under和超出目标的超额over两个非负变量:
IntVar[] under = new IntVar[numEmployees]; IntVar[] over = new IntVar[numEmployees]; for (int e = 0; e < numEmployees; e++) { under[e] = model.NewIntVar(0, employeeTargetHours[e], $"under_{e}"); over[e] = model.NewIntVar(0, employeeTargetHours[e], $"over_{e}"); // 约束保证under和over不会同时为正,二者分别代表低于/超出目标的时长 model.Add(actualHours[e] + under[e] - over[e] == employeeTargetHours[e]); }
步骤3:构造最小化总偏差的目标函数
总偏差为所有员工的缺额和超额之和,最小化该值即可让每位员工的实际工时尽可能接近目标:
List<LinearExpr> allDeviations = new List<LinearExpr>(); allDeviations.AddRange(under); allDeviations.AddRange(over); model.Minimize(LinearExpr.Sum(allDeviations));
如果业务上对缺额/超额的容忍度不同,还可以给不同偏差设置权重,比如更希望避免员工加班的话,可以调整为:
// 给超额偏差设置2倍权重,求解器会优先控制加班时长 model.Minimize(LinearExpr.Sum(under) + 2 * LinearExpr.Sum(over));
内容的提问来源于stack exchange,提问作者Nicolas Salomon
相关产品推荐
相关产品推荐

