护士排班问题与或工具,分配超过 1 名护士轮班

问题描述

我正在修改 here 中的代码 ,我希望能够根据工人的喜好创建一个轮班时间表,该时间表将分配给早晚班的 2 名工人和夜班的一名工人。 这是原始代码

def create_shifts():
    num_nurses = 5
    num_days = 7
    num_shifts = 3
    all_nurses = range(num_nurses)
    all_shifts = range(num_shifts)
    all_days = range(num_days)
    shift_requests,workers_names = pre_condition_for_creating_shifts(num_nurses,num_days,num_shifts)
    # Creates the model.
    model = cp_model.CpModel()

    # Creates shift variables.
    # shifts[(n,d,s)]: nurse 'n' works shift 's' on day 'd'.
    shifts = {}
    for n in all_nurses:
        for d in all_days:
            for s in all_shifts:
                shifts[(n,s)] = model.NewBoolVar('shift_n%id%is%i' % (n,s))

    # Each shift is assigned to exactly one nurse in.
    for d in all_days:
        for s in all_shifts:

            model.Add(sum(shifts[(n,s)] for n in all_nurses) == 1)

    # Each nurse works at most one shift per day.
    for n in all_nurses:
        for d in all_days:
            model.Add(sum(shifts[(n,s)] for s in all_shifts) <= 1)

    # Try to distribute the shifts evenly,so that each nurse works
    # min_shifts_per_nurse shifts. If this is not possible,because the total
    # number of shifts is not divisible by the number of nurses,some nurses will
    # be assigned one more shift.
    min_shifts_per_nurse = (num_shifts * num_days) // num_nurses
    if num_shifts * num_days % num_nurses == 0:
        max_shifts_per_nurse = min_shifts_per_nurse
    else:
        max_shifts_per_nurse = min_shifts_per_nurse + 1
    for n in all_nurses:
        num_shifts_worked = 0
        for d in all_days:
            for s in all_shifts:
                num_shifts_worked += shifts[(n,s)]
        model.Add(min_shifts_per_nurse <= num_shifts_worked)
        model.Add(num_shifts_worked <= max_shifts_per_nurse)

    final_shifts = []
    id = []
    # pylint: disable=g-complex-comprehension
    model.Maximize(sum(shift_requests[n][d][s] * shifts[(n,s)] for n in all_nurses for d in all_days for s in all_shifts))
    # Creates the solver and solve.
    solver = cp_model.cpsolver()
    solver.solve(model)
    for s in all_shifts:
        for d in all_days:
            print('Day',d)
            for n in all_nurses:
                if solver.Value(shifts[(n,s)]) == 1:
                    if shift_requests[n][d][s] == 1:
                        final_shifts.append(workers_names[n])
                        print('Worker',n,'works shift',s,'(requested).')
                    else:
                        final_shifts.append("No submitted")
                        print('Worker','(not requested).')
        print()
    post_condition_for_creating_shifts(final_shifts)

    # Statistics.
    print()
    print('Statistics')
    print('  - Number of shift requests met = %i' % solver.ObjectiveValue(),'(out of',num_nurses * min_shifts_per_nurse,')')
    print('  - wall time       : %f s' % solver.WallTime())

代替:

    # Each shift is assigned to exactly one nurse in.
    for d in all_days:
        for s in all_shifts:

            model.Add(sum(shifts[(n,s)] for n in all_nurses) == 1)``

我已经改变了这个:

 for d in all_days:
        for s in all_shifts:
            if s==0 or s==1:
                model.Add(sum(shifts[(n,s)] for n in all_nurses) == 2)
            else:
                model.Add(sum(shifts[(n,s)] for n in all_nurses) == 1)
    # Each nurse works at most one shift per day.
    for n in all_nurses:
        week=[]
        for d in all_days:
            for s in all_shifts:
                week.append(shifts[(n,s)])
                # week.append(sum(shifts[(n,s)] for s in all_shifts))
            model.Add(sum(week) >= 1)
            model.Add(sum(week) <= 5)

但我在行中遇到错误

   if solver.Value(shifts[(n,s)]) == 1:

那句话:IndexError: list index out of range

解决方法

当前的示例非常有限,因为它使用了轮班次数等于护士人数的假设。对于更完整的示例,我建议查看此示例:

https://github.com/google/or-tools/blob/stable/examples/python/shift_scheduling_sat.py