Python实现7员工7周多约束排班并输出至CSV
7周员工排班问题的Python实现方案
需求回顾
- 7名员工,7周(49天),每天3个班次:早班(M)、中班(A)、晚班(N)
- 约束1:每天的三个班次必须由不同员工负责
- 约束2:每个员工在49天内,每个工作日的每个班次仅排1次(如员工1仅排1次周一早班、1次周一中班等)
- 约束3:员工值晚班后,后续2天不得排班
实现思路
采用贪心算法逐天排班,优先处理晚班(因晚班有禁排约束),确保每一步选择都满足所有约束:
- 跟踪每个员工已排过的(工作日, 班次)组合,确保不违反约束2
- 跟踪每个员工的禁排日期,确保晚班后两天不排班(约束3)
- 每天的班次选择不同员工,满足约束1
完整代码
import csv import random # 配置参数 EMPLOYEES = [f"员工{i+1}" for i in range(7)] SHIFTS = ["M", "A", "N"] DAYS_PER_WEEK = 7 TOTAL_DAYS = 7 * DAYS_PER_WEEK WEEKDAY_NAMES = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"] def generate_schedule(): # 记录每个员工已排的(工作日, 班次)组合 emp_shift_history = {emp: set() for emp in EMPLOYEES} # 记录每个员工的禁排日期 emp_blocked_days = {emp: set() for emp in EMPLOYEES} # 每日排班结果 daily_schedule = {day: {} for day in range(TOTAL_DAYS)} for day_idx in range(TOTAL_DAYS): current_weekday = day_idx % DAYS_PER_WEEK used_emps = set() # 优先排晚班,因为有禁排约束 for shift in ["N", "A", "M"]: # 筛选符合条件的员工 candidates = [ emp for emp in EMPLOYEES if emp not in used_emps and day_idx not in emp_blocked_days[emp] and (current_weekday, shift) not in emp_shift_history[emp] ] if not candidates: raise ValueError(f"无法为第{day_idx+1}天的{shift}班找到合适员工,请调整排班策略") # 随机选择候选员工(可改为按固定顺序选择,提升稳定性) selected_emp = random.choice(candidates) # 更新记录 daily_schedule[day_idx][shift] = selected_emp used_emps.add(selected_emp) emp_shift_history[selected_emp].add((current_weekday, shift)) # 晚班后添加两天禁排期 if shift == "N": if day_idx + 1 < TOTAL_DAYS: emp_blocked_days[selected_emp].add(day_idx + 1) if day_idx + 2 < TOTAL_DAYS: emp_blocked_days[selected_emp].add(day_idx + 2) return daily_schedule def export_to_csv(schedule, filename="员工排班表.csv"): with open(filename, "w", encoding="utf-8-sig", newline="") as csvfile: writer = csv.writer(csvfile) # 写入表头 writer.writerow(["日期", "星期", "早班(M)", "中班(A)", "晚班(N)"]) for day_idx in range(TOTAL_DAYS): week_num = (day_idx // DAYS_PER_WEEK) + 1 weekday = WEEKDAY_NAMES[day_idx % DAYS_PER_WEEK] date_label = f"第{week_num}周{weekday}" m_emp = schedule[day_idx]["M"] a_emp = schedule[day_idx]["A"] n_emp = schedule[day_idx]["N"] writer.writerow([date_label, weekday, m_emp, a_emp, n_emp]) if __name__ == "__main__": try: schedule = generate_schedule() export_to_csv(schedule) print("排班表生成成功,已保存为'员工排班表.csv'") except ValueError as e: print(f"生成失败:{e}")
注意事项
- 代码中使用
random.choice选择员工,若出现无法找到候选的情况,可改为按固定顺序选择员工(如遍历EMPLOYEES列表取第一个符合条件的),提升排班稳定性 - 若需要更优的排班分布(如员工排班间隔更均匀),可调整候选员工的排序逻辑(如优先选择剩余排班次数最多的员工)
- 生成的CSV文件使用
utf-8-sig编码,确保Excel打开时无乱码
内容的提问来源于stack exchange,提问作者Lorenzo Epifani
相关产品推荐
相关产品推荐

