添加 'at least one day off' 约束
Adding 'at least one day off' constraint
我在下面简化了我正在尝试做的事情的例子。我有一个每周计划和一些不同的 'slots' 来填补,我正在最大化分配给每个槽的每个人的给定值。
我正在尝试添加一个约束条件,表示他们每人休息一天。我见过类似的问题,但我无法将它们翻译成这个问题,因此不胜感激。
我的想法是,我可以取每个人每天的最大值,即在他们当前分配的任何一天都为 1,然后对所有天数求和并尝试使其小于或等于到 2(共 3 天)。
from ortools.sat.python import cp_model
model = cp_model.CpModel()
assignments = {}
people = ['Max','Josh']
days = {
'Monday':['7','8','9','10'],
'Tuesday':['6','7','8','9','10'],
'Wednesday':['7','8','9','10']
}
default_thing_we_like = 50
thing_we_like_per_employee_per_slot = {
('Max','Monday','7'): 100,
('Max','Tuesday','7'): 150,
('Max','Wednesday','7'): 200,
}
# make vars
for person in people:
for day in days:
for hour in days[day]:
assignments[(person,day,hour)] = model.NewBoolVar(f'{person}-{day}-{hour}')
# fill each spot
for day in days:
for hour in days[day]:
model.Add(sum(assignments[(person,day,hour)] for person in people) == 1)
# everyone should get at least one of these days off
for person in people:
for day in days:
model.Add(sum(max(assignments.get((person,day,hour),0) for hour in days[day]) for day in days) <= 2)
solver = cp_model.CpSolver()
model.Maximize(sum(thing_we_like_per_employee_per_slot.get((person, day, hour),default_thing_we_like) * assignments[(person,day,hour)]
for hour in days[day]
for day in days
for person in people
))
solution_printer = cp_model.ObjectiveSolutionPrinter()
status = solver.SolveWithSolutionCallback(model, solution_printer)
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
ret_slots = []
for person in people:
print(f"{person} is working: ")
for day in days:
for hour in days[day]:
if (solver.Value(assignments[(person,day,hour)])):
print(f"{day} at {hour} with",thing_we_like_per_employee_per_slot.get((person, day, hour),default_thing_we_like),"things we like.")
else:
print("uh oh")
我得到的结果运行是这样的:
Solution 0, time = 0.00 s, objective = 900
Max is working:
Monday at 7 with 100 things we like.
Monday at 9 with 50 things we like.
Tuesday at 6 with 50 things we like.
Tuesday at 7 with 150 things we like.
Tuesday at 8 with 50 things we like.
Tuesday at 9 with 50 things we like.
Tuesday at 10 with 50 things we like.
Wednesday at 7 with 200 things we like.
Wednesday at 8 with 50 things we like.
Wednesday at 9 with 50 things we like.
Wednesday at 10 with 50 things we like.
Josh is working:
Monday at 8 with 50 things we like.
Monday at 10 with 50 things we like.
它将 Max 分配给所有 3 天。
您不能将 max, min, or, and
与 ortools 创建的变量一起使用。
要对这些类型的约束进行建模,只需创建中间变量会更容易。
works_day = {
(person, day): model.NewBoolVar(f"{person}-{day}")
for person in people
for day in days
}
for person in people:
for day in days:
for hour in days[day]:
assignments[(person, day, hour)] = model.NewBoolVar(
f"{person}-{day}-{hour}"
)
model.AddImplication(
assignments[(person, day, hour)], works_day[person, day]
)
for person in people:
model.Add(sum(works_day[person, day] for day in days) <= 2)
我在下面简化了我正在尝试做的事情的例子。我有一个每周计划和一些不同的 'slots' 来填补,我正在最大化分配给每个槽的每个人的给定值。
我正在尝试添加一个约束条件,表示他们每人休息一天。我见过类似的问题,但我无法将它们翻译成这个问题,因此不胜感激。
我的想法是,我可以取每个人每天的最大值,即在他们当前分配的任何一天都为 1,然后对所有天数求和并尝试使其小于或等于到 2(共 3 天)。
from ortools.sat.python import cp_model
model = cp_model.CpModel()
assignments = {}
people = ['Max','Josh']
days = {
'Monday':['7','8','9','10'],
'Tuesday':['6','7','8','9','10'],
'Wednesday':['7','8','9','10']
}
default_thing_we_like = 50
thing_we_like_per_employee_per_slot = {
('Max','Monday','7'): 100,
('Max','Tuesday','7'): 150,
('Max','Wednesday','7'): 200,
}
# make vars
for person in people:
for day in days:
for hour in days[day]:
assignments[(person,day,hour)] = model.NewBoolVar(f'{person}-{day}-{hour}')
# fill each spot
for day in days:
for hour in days[day]:
model.Add(sum(assignments[(person,day,hour)] for person in people) == 1)
# everyone should get at least one of these days off
for person in people:
for day in days:
model.Add(sum(max(assignments.get((person,day,hour),0) for hour in days[day]) for day in days) <= 2)
solver = cp_model.CpSolver()
model.Maximize(sum(thing_we_like_per_employee_per_slot.get((person, day, hour),default_thing_we_like) * assignments[(person,day,hour)]
for hour in days[day]
for day in days
for person in people
))
solution_printer = cp_model.ObjectiveSolutionPrinter()
status = solver.SolveWithSolutionCallback(model, solution_printer)
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE:
ret_slots = []
for person in people:
print(f"{person} is working: ")
for day in days:
for hour in days[day]:
if (solver.Value(assignments[(person,day,hour)])):
print(f"{day} at {hour} with",thing_we_like_per_employee_per_slot.get((person, day, hour),default_thing_we_like),"things we like.")
else:
print("uh oh")
我得到的结果运行是这样的:
Solution 0, time = 0.00 s, objective = 900
Max is working:
Monday at 7 with 100 things we like.
Monday at 9 with 50 things we like.
Tuesday at 6 with 50 things we like.
Tuesday at 7 with 150 things we like.
Tuesday at 8 with 50 things we like.
Tuesday at 9 with 50 things we like.
Tuesday at 10 with 50 things we like.
Wednesday at 7 with 200 things we like.
Wednesday at 8 with 50 things we like.
Wednesday at 9 with 50 things we like.
Wednesday at 10 with 50 things we like.
Josh is working:
Monday at 8 with 50 things we like.
Monday at 10 with 50 things we like.
它将 Max 分配给所有 3 天。
您不能将 max, min, or, and
与 ortools 创建的变量一起使用。
要对这些类型的约束进行建模,只需创建中间变量会更容易。
works_day = {
(person, day): model.NewBoolVar(f"{person}-{day}")
for person in people
for day in days
}
for person in people:
for day in days:
for hour in days[day]:
assignments[(person, day, hour)] = model.NewBoolVar(
f"{person}-{day}-{hour}"
)
model.AddImplication(
assignments[(person, day, hour)], works_day[person, day]
)
for person in people:
model.Add(sum(works_day[person, day] for day in days) <= 2)