0

I had few data about tasks showing about every task and how long the task is, for e.g.:

Table 1:

Tasks Length Time
Task 1 45 mins 6:30
Task 2 45 mins 7:00

Here I know about every task, how long the task is, and at what time the task is to be done. Now I have 10 crews for an instance, 7 are on a contract basis who have different payroll per hour than the regular ones. I need to assign every task to all the crews accordingly. There can be no overlap. One task is assigned to a single Crew only. There are 200 tasks as such. Is there a particular python package or even algorithm that can help me with this? I came across this. But I am not sure this could help me accordingly. Is there any such other algorithm that could help me with this problem?

  • Scheduling problems are often solved by Dynamic Programming algorithms. In fact, such problems are used in some famous books to introduce Dynamic Programming. You might want to check those algorithms. – Deep Mar 28 '21 at 16:56

1 Answers1

0

You could formulate the problem in CP Optimizer as follows. It even generalizes the problem to the case of tasks whose start date is not fixed but has to be decided in a time window.

from docplex.cp.model import *

# Time hh:mm to minute
def mn(time):
    h,m = time.split(':')
    return 60*int(h)+int(m)

T = [
  # Length, Earliest start, Latest start
  (45, mn("6:30"),  mn("6:30")),
  (45, mn("7:00"),  mn("7:10")),
  #...
]

# Cost of crew (per minute)
C = [ 10, 12, 11, 12, 13 ]

N = range(len(T)) # Number of nbTasks
M = range(len(C)) # Number of resources (crews)

# CP Optimizer formulation

model = CpoModel()

# Decision variables:
# task[i]    : interval variable representing task i
# alloc[i][j]: optional interval variable representing task i allocated to crew j
task  = [ interval_var(size=T[i][0], start=[T[i][1],T[i][2]], name="T{}".format(i)) for i in N]
alloc = [ [interval_var(optional=True, name="T{}R{}".format(i,j)) for j in M] for i in N]

# Each task must be allocated one and only one crew:
model.add([alternative(task[i], [alloc[i][j] for j in M]) for i in N])
# Tasks performed by a crew do not overlap
model.add([no_overlap([alloc[i][j] for i in N]) for j in M])
# No more than M tasks executed in parallel (this is a redundant constraint)
model.add(sum(pulse(task[i],1) for i in N) <= len(C))

# Minimize total allocation cost
cost = sum(C[j]*length_of(alloc[i][j]) for i in N for j in M)
model.add(minimize(cost))

# CP Optimizer resolution

solution = model.solve(LogPeriod=1000000, TimeLimit=30)

# Display solution

for i in N:
    for j in M:
        s = solution.get_var_solution(alloc[i][j])
        if s.is_present():
            print("Task {} scheduled on {}-{} with crew {}".format(i,s.get_start(),s.get_end(),j))

Will display something like:

Task 0 scheduled on 390-435 with crew 0
Task 1 scheduled on 420-465 with crew 2