Workforce Scheduling#
이강우 & 김정자. (2012). EXCEL 2010 경영과학. 한경사, 233.
K항공에서는 최근 여행객의 증가로 인천국제공항에 기항하거나 출항하는 비행기를 증편시키려고 하며 이에 따라서 추가로 서비스 직원을 고용하려고 한다. Table 1은 새로 증편된 운항계획에 따라서 각 교대조별 근무시간, 시간대별 필요한 직원의 소요인원 및 교대조별 1명당 1일 노무비용을 조사한 결과이다. 한편 K항공의 서비스 직원은 1일 8시간 단위로 근무하며 각 교대조의 근무시간은 다음과 같다.
Table 1 교대조별 근무시간대와 근무시간대별 소요인원
근무시간대 |
교대조1 |
교대조2 |
교대조3 |
교대조4 |
교대조5 |
소요인원(명) |
---|---|---|---|---|---|---|
06:00 ~ 08:00 |
O |
48 |
||||
08:00 ~ 10:00 |
O |
O |
79 |
|||
10:00 ~ 12:00 |
O |
O |
65 |
|||
12:00 ~ 14:00 |
O |
O |
O |
87 |
||
14:00 ~ 16:00 |
O |
O |
64 |
|||
16:00 ~ 18:00 |
O |
O |
73 |
|||
18:00 ~ 20:00 |
O |
O |
82 |
|||
20:00 ~ 22:00 |
O |
43 |
||||
22:00 ~ 24:00 |
O |
O |
52 |
|||
24:00 ~ 06:00 |
O |
15 |
||||
1인당 임금(만원) |
7 |
6 |
7.5 |
8 |
9.5 |
import os
import sys
# Add the parent directory for importing custom library
sys.path.insert(0, os.path.abspath(os.path.join(os.getcwd(), os.pardir)))
Optimization with PuLP#
from pulp import *
from ortools.utils import output
# Define problem
prob = LpProblem(name='Workforce Scheduling', sense=LpMinimize)
# Create decision variables and non-negative constraint
x1 = LpVariable(name='X1', lowBound=0, cat='Continuous')
x2 = LpVariable(name='X2', lowBound=0, cat='Continuous')
x3 = LpVariable(name='X3', lowBound=0, cat='Continuous')
x4 = LpVariable(name='X4', lowBound=0, cat='Continuous')
x5 = LpVariable(name='X5', lowBound=0, cat='Continuous')
# Set objective function
prob += 7*x1 + 6*x2 + 7.5*x3 + 8*x4 + 9.5*x5
# Set constraints
prob += x1 >= 48
prob += x1 + x2 >= 79
prob += x1 + x2 >= 65
prob += x1 + x2 + x3 >= 87
prob += x2 + x3 >= 64
prob += x3 + x4 >= 73
prob += x3 + x4 >= 82
prob += x4 >= 43
prob += x4 + x5 >= 52
prob += x5 >= 15
# Solving problem
prob.solve()
output(prob, sensitivity=False)
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[2], line 1
----> 1 from pulp import *
2 from ortools.utils import output
4 # Define problem
ModuleNotFoundError: No module named 'pulp'
from pulp import *
from ortools.utils import output
n_shifts = 5
costs = [7, 6, 7.5, 8, 9.5]
needs = [48, 79, 65, 87, 64, 73, 82, 43, 52, 15]
table = [
[1, 0, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 1]
]
# Define problem
prob = LpProblem(name='Workforce Scheduling', sense=LpMinimize)
# Create decision variables and non-negative constraint
x = [LpVariable('X{}'.format(i), lowBound=0) for i in range(n_shifts)]
# Set objective function
prob += lpSum([costs[i]*x[i] for i in range(n_shifts)])
for i in range(len(table)):
prob += lpSum([x[j] for j in range(n_shifts) if table[i][j] == 1]) >= needs[i]
# Solving problem
prob.solve()
output(prob, sensitivity=False)
Status: Optimal
Objective value: 1301.0
Variables Values
----------- --------
X0 48
X1 31
X2 39
X3 43
X4 15
Statistics:
- Number of variables: 5
- Number of constraints: 10
- Solve time: 0.017s
Optimization with GUROBI#
from gurobipy import *
from ortools.utils import set_gurobi, custom_callback, output
n_shifts = 5
costs = [7, 6, 7.5, 8, 9.5]
needs = [48, 79, 65, 87, 64, 73, 82, 43, 52, 15]
table = [
[1, 0, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 0, 1, 1, 0],
[0, 0, 1, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 1]
]
m = Model('Workforce Scheduling')
x = [m.addVar(vtype=GRB.CONTINUOUS, name='X{}'.format(i)) for i in range(n_shifts)]
m.update()
m.setObjective(quicksum(costs[i]*x[i] for i in range(n_shifts)), GRB.MINIMIZE)
for i in range(len(table)):
m.addConstr(quicksum(x[j] for j in range(n_shifts) if table[i][j] == 1) >= needs[i])
set_gurobi(m, verbose=False)
# Optimize model
m.optimize(custom_callback)
output(m)
Status: Optimal
Objective value: 1301.0
Variables Values
----------- --------
X0 48
X1 31
X2 39
X3 43
X4 15
Statistics:
- Number of variables: 5
- Number of constraints: 10
- Solve time: 0.000s