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

如何基于行列条件填充排班矩阵(已更新2次)

解决R语言排班规划的约束问题

针对你的需求,我们可以分月份处理休息日分配,确保每个工人每月休息8天,同时每天恰好8人在岗。下面是完整的实现步骤和代码:

步骤说明

  • 拆分日期为对应月份,明确每个月的天数(2023年2月28天,3月31天)
  • 对每个月份单独处理:先给每个工人随机分配8个休息日,再调整每日在岗人数至要求的8人,同时不破坏每个工人的休息天数限制

完整代码

# 初始参数
n <- 12          # 工人数
np <- 8          # 每日在岗人数
r <- 8           # 每人每月休息天数
vday <- seq(as.Date('2023-02-01'), as.Date('2023-03-31'), by = 1)
mm <- matrix(data = NA, nrow = n, ncol = length(vday))
dimnames(mm)[[2]] <- as.character(vday)

# 拆分月份:2023年2月和3月
feb_days <- vday[format(vday, "%Y-%m") == "2023-02"]
mar_days <- vday[format(vday, "%Y-%m") == "2023-03"]
feb_cols <- which(colnames(mm) %in% as.character(feb_days))
mar_cols <- which(colnames(mm) %in% as.character(mar_days))

# 处理单月排班的函数
assign_month_shifts <- function(month_cols, month_day_count) {
  # 初始化该月矩阵:先全设为在岗(1)
  month_mat <- matrix(1, nrow = n, ncol = length(month_cols))
  
  # 给每个工人随机分配r个休息日
  for (worker in 1:n) {
    rest_days <- sample(1:length(month_cols), size = r)
    month_mat[worker, rest_days] <- 0
  }
  
  # 调整每日在岗人数至np
  for (day in 1:length(month_cols)) {
    current_on_duty <- sum(month_mat[, day])
    
    if (current_on_duty > np) {
      # 在岗人数过多:随机选多余的人改成休息,且确保该工人当月休息天数不超过r
      excess <- current_on_duty - np
      eligible_workers <- which(month_mat[, day] == 1 & rowSums(month_mat == 0) < r)
      if (length(eligible_workers) >= excess) {
        selected <- sample(eligible_workers, size = excess)
        month_mat[selected, day] <- 0
      }
    } else if (current_on_duty < np) {
      # 在岗人数不足:随机选休息的人改成在岗,且确保该工人当月休息天数不低于r
      deficit <- np - current_on_duty
      eligible_workers <- which(month_mat[, day] == 0 & rowSums(month_mat == 1) < (month_day_count - r))
      if (length(eligible_workers) >= deficit) {
        selected <- sample(eligible_workers, size = deficit)
        month_mat[selected, day] <- 1
      }
    }
  }
  
  return(month_mat)
}

# 分配2月和3月的班次
mm[, feb_cols] <- assign_month_shifts(feb_cols, length(feb_days))
mm[, mar_cols] <- assign_month_shifts(mar_cols, length(mar_days))

# 验证约束是否满足
# 检查每个工人每月休息天数
feb_rest_counts <- rowSums(mm[, feb_cols] == 0)
mar_rest_counts <- rowSums(mm[, mar_cols] == 0)
cat("2月每人休息天数:", feb_rest_counts, "\n")
cat("3月每人休息天数:", mar_rest_counts, "\n")

# 检查每日在岗人数
daily_on_duty <- colSums(mm)
cat("每日在岗人数:", daily_on_duty, "\n")

代码解释

  • 月份拆分:将总日期拆分为2月和3月,确保每月的休息天数计算独立
  • 初始休息日分配:先给每个工人随机选8天休息,保证每人每月基础休息天数达标
  • 每日人数调整:针对不符合在岗人数要求的日期,在不违反工人每月休息天数限制的前提下,调整人员的在岗/休息状态,确保每天恰好8人在岗
  • 验证环节:最后输出每个工人的月休息天数和每日在岗人数,确认所有约束都被满足

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:40:20