from ortools.sat.python import cp_model
people = ["阿明", "小華", "美玲", "志強", "雅婷"]
days = 7
shifts = ["早", "晚"]
need = {"早": 2, "晚": 1}
off = {("美玲", 2), ("志強", 5)} # 請假,天數從 0 開始算
m = cp_model.CpModel()
x = {(p, d, s): m.new_bool_var(f"{p}_{d}_{s}") for p in people for d in range(days) for s in shifts}
for d in range(days):
for s in shifts:
m.add(sum(x[p, d, s] for p in people) == need[s]) # 每班人數
for p in people:
m.add(sum(x[p, d, s] for s in shifts) <= 1) # 一天最多一班
for p in people:
for d in range(days - 1):
m.add(x[p, d, "晚"] + x[p, d + 1, "早"] <= 1) # 晚班隔天不接早班
for p, d in off:
for s in shifts:
m.add(x[p, d, s] == 0)
total = {p: sum(x[p, d, s] for d in range(days) for s in shifts) for p in people}
most = m.new_int_var(0, days, "most")
least = m.new_int_var(0, days, "least")
for p in people:
m.add(total[p] <= 5) # 一週最多 5 班
m.add(total[p] <= most)
m.add(total[p] >= least)
m.minimize(most - least) # 班數越平均越好
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 10
status = solver.solve(m)
print(solver.status_name(status))
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
for d in range(days):
row = {s: [p for p in people if solver.value(x[p, d, s])] for s in shifts}
print(f"第{d + 1}天", row)