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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 15:54:04