添加“至少一天休假”约束

时间:2019-12-18 16:43:34

标签: python or-tools

我在下面简化了一个示例。我有一个每周的时间表,还有几个不同的“空位”要填写,在这里我将分配给每个空位的人的给定值最大化。

我正在尝试添加一个约束条件,规定他们每个人都有一天假。我曾经看到过类似的问题,但是我很难将其翻译成这个问题,因此我们将不胜感激。

我的想法是,我可以将每个人每天的最大值取为当前分配给他们的任何一天的最大值,然后将所有这些天的最大值相加,并尝试使该最大值小于或等于2 (三天之内)。

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.

它将全部三天分配为最大值。

1 个答案:

答案 0 :(得分:2)

您不能将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)