Формулировка модели планирования медсестры в AMPL
Я работал над проблемой планирования медсестры в AMPL для следующих условий:
Всего № медсестер =20
Всего № дерьмо = 3 # утро, день, ночь
Горизонт планирования 7 дней: скажем, M T W R F Sa Su
Наряду со следующими ограничениями:
- Макс № рабочих дней в неделю: 5
- Отдых дней после 4 непрерывных ночных смен.
- Последовательные ночные и утренние смены не допускаются.
- Спрос в смену составляет 7 медсестер.
- Медсестра может работать только в одну смену в день, то есть утром, ночью, днем
Сценарии затрат:
Morning shift: $12
Day shift: $13
Night shift : $15
Задача - минимизировать стоимость операции в соответствии с предпочтениями медсестры.
Кто-нибудь может дать мне представление о том, как можно сформулировать эту проблему?
2 ответа
set nurse; #no. of full time employees working in the facility
set days; #planning horizon
set shift; #no. of shift in a day
set S; #shift correseponding to the outsourced nurses
set D;#day corresponding to the outsourced nurses
set N;#
# ith nurse working on day j
# j starts from Monday (j=1), Tuesday( j=2), Wednesday (j=3), Thursday(j=4), Friday(j=5), Saturday(j=6), Sunday(j=7)
#s be the shift as morning, day and night
param availability{i in nurse, j in days};
param costpershift{i in nurse, j in days, s in shift};
param outcost{n in N, l in D, m in S};
var nurseavailability{i in nurse,j in days,s in shift} binary; # = 1 if nurse i is available on jth day working on sth shift, 0 otherwise
var outsourced{n in N, l in D, m in S} integer;
#Objective function
minimize Cost: sum{i in nurse, j in days, s in shift} costpershift[i,j,s]*nurseavailability[i,j,s]+ sum{ n in N, l in D, m in S}outcost[n,l,m]*outsourced[n,l,m];
#constraints
#maximum no. of shifts per day
subject to maximum_shifts_perday {i in nurse,j in days}:
sum{s in shift} nurseavailability[i,j,s]*availability[i,j] <= 1;
#maximum no. of working says a week
subject to maximum_days_of_work {i in nurse}:
sum{j in days,s in shift} availability[i,j]*nurseavailability[i,j,s]<=5; #maximum working days irrespective of shifts
# rest days after night shifts
subject to rest_days_after_night_shift{i in nurse}:
sum{j in days} availability[i,j]*nurseavailability[i,j,3]<=4;
#demand per shift
subject to supply{j in days, s in shift, l in D, m in S}:
sum{i in nurse} availability[i,j]*nurseavailability[i,j,s] + sum{n in N} outsourced[n,l,m]=7;
#outsourcing only works well when there is more variability in supply.
#increasing the staff no. would be effective for reducing the cost variability in demand.
#considering a budget of $16,000 per week
#outsourcing constraints: a maximum of 20 nurses can be outsourced per shift
# no. of fulltime employees=30
#demand is 7 nurses per shift
#the average variability
#all nurses are paid equally @ $12 per hour.
#cost of an outsourced shift is $144.
#cost of morning shift is $96.
#cost of day shift is $104.
#cost of night shift is $120.
data;
#set nurse ordered:= nurse1 nurse2 nurse3 nurse4 nurse5 nurse6 nurse7 nurse8
#nurse9 nurse10 nurse11 nurse12 nurse13 nurse14 nurse15 nurse16 nurse17
#nurse18 nurse19 nurse20;
set nurse:= 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30;
#set days ordered:= Monday Tuesday Wednesday Thursday Friday Saturday Sunday;
set days:= 1 2 3 4 5 6 7;
#set shift ordered:= Morning Day Night;
set shift:= 1 2 3;
set D:= 1 2 3 4 5 6 7; #outsourced days
set S:=1 2 3; #outshit
set N := 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20;
param outcost
[*,*,1]:
1 2 3 4 5 6 7:=
1 144 144 144 144 144 144 144
2 144 144 144 144 144 144 144
3 144 144 144 144 144 144 144
4 144 144 144 144 144 144 144
5 144 144 144 144 144 144 144
6 144 144 144 144 144 144 144
7 144 144 144 144 144 144 144
8 144 144 144 144 144 144 144
9 144 144 144 144 144 144 144
10 144 144 144 144 144 144 144
11 144 144 144 144 144 144 144
12 144 144 144 144 144 144 144
13 144 144 144 144 144 144 144
14 144 144 144 144 144 144 144
15 144 144 144 144 144 144 144
16 144 144 144 144 144 144 144
17 144 144 144 144 144 144 144
18 144 144 144 144 144 144 144
19 144 144 144 144 144 144 144
20 144 144 144 144 144 144 144
[*,*,2]:
1 2 3 4 5 6 7:=
1 144 144 144 144 144 144 144
2 144 144 144 144 144 144 144
3 144 144 144 144 144 144 144
4 144 144 144 144 144 144 144
5 144 144 144 144 144 144 144
6 144 144 144 144 144 144 144
7 144 144 144 144 144 144 144
8 144 144 144 144 144 144 144
9 144 144 144 144 144 144 144
10 144 144 144 144 144 144 144
11 144 144 144 144 144 144 144
12 144 144 144 144 144 144 144
13 144 144 144 144 144 144 144
14 144 144 144 144 144 144 144
15 144 144 144 144 144 144 144
16 144 144 144 144 144 144 144
17 144 144 144 144 144 144 144
18 144 144 144 144 144 144 144
19 144 144 144 144 144 144 144
20 144 144 144 144 144 144 144
[*,*,3]:
1 2 3 4 5 6 7:=
1 144 144 144 144 144 144 144
2 144 144 144 144 144 144 144
3 144 144 144 144 144 144 144
4 144 144 144 144 144 144 144
5 144 144 144 144 144 144 144
6 144 144 144 144 144 144 144
7 144 144 144 144 144 144 144
8 144 144 144 144 144 144 144
9 144 144 144 144 144 144 144
10 144 144 144 144 144 144 144
11 144 144 144 144 144 144 144
12 144 144 144 144 144 144 144
13 144 144 144 144 144 144 144
14 144 144 144 144 144 144 144
15 144 144 144 144 144 144 144
16 144 144 144 144 144 144 144
17 144 144 144 144 144 144 144
18 144 144 144 144 144 144 144
19 144 144 144 144 144 144 144
20 144 144 144 144 144 144 144;
param availability:
1 2 3 4 5 6 7 :=
1 0 0 0 0 0 0 0
2 1 1 1 1 1 1 1
3 1 1 1 1 1 1 1
4 1 1 1 1 1 1 1
5 1 1 1 1 1 1 1
6 1 1 1 1 1 1 1
7 1 0 1 1 1 1 1
8 1 1 1 1 1 1 1
9 1 1 1 1 1 1 1
10 1 1 1 1 1 1 1
11 1 1 1 1 1 1 1
12 1 1 1 1 1 1 1
13 1 1 1 1 1 1 1
14 1 1 1 1 1 1 1
15 1 1 1 1 1 1 1
16 1 1 1 1 1 1 1
17 0 1 1 1 1 1 1
18 1 1 1 1 1 1 1
19 1 1 1 1 1 1 1
20 1 1 1 1 1 1 1
21 1 1 1 1 1 1 1
22 1 1 1 1 1 1 1
23 1 1 1 1 1 1 1
24 1 1 1 1 1 1 1
25 1 1 1 1 1 1 1
26 1 1 1 1 1 1 1
27 1 1 1 1 1 1 1
28 1 1 1 1 1 1 1
29 1 1 1 1 1 1 1
30 1 1 1 1 1 1 1;
param costpershift:=
[*,*,1]: 1 2 3 4 5 6 7 :=
1 96 96 96 96 96 96 96
2 96 96 96 96 96 96 96
3 96 96 96 96 96 96 96
4 96 96 96 96 96 96 96
5 96 96 96 96 96 96 96
6 96 96 96 96 96 96 96
7 96 96 96 96 96 96 96
8 96 96 96 96 96 96 96
9 96 96 96 96 96 96 96
10 96 96 96 96 96 96 96
11 96 96 96 96 96 96 96
12 96 96 96 96 96 96 96
13 96 96 96 96 96 96 96
14 96 96 96 96 96 96 96
15 96 96 96 96 96 96 96
16 96 96 96 96 96 96 96
17 96 96 96 96 96 96 96
18 96 96 96 96 96 96 96
19 96 96 96 96 96 96 96
20 96 96 96 96 96 96 96
21 96 96 96 96 96 96 96
22 96 96 96 96 96 96 96
23 96 96 96 96 96 96 96
24 96 96 96 96 96 96 96
25 96 96 96 96 96 96 96
26 96 96 96 96 96 96 96
27 96 96 96 96 96 96 96
28 96 96 96 96 96 96 96
29 96 96 96 96 96 96 96
30 96 96 96 96 96 96 96
[*,*,2] : 1 2 3 4 5 6 7 :=
1 104 104 104 104 104 104 104
2 104 104 104 104 104 104 104
3 104 104 104 104 104 104 104
4 104 104 104 104 104 104 104
5 104 104 104 104 104 104 104
6 104 104 104 104 104 104 104
7 104 104 104 104 104 104 104
8 104 104 104 104 104 104 104
9 104 104 104 104 104 104 104
10 104 104 104 104 104 104 104
11 104 104 104 104 104 104 104
12 104 104 104 104 104 104 104
13 104 104 104 104 104 104 104
14 104 104 104 104 104 104 104
15 104 104 104 104 104 104 104
16 104 104 104 104 104 104 104
17 104 104 104 104 104 104 104
18 104 104 104 104 104 104 104
19 104 104 104 104 104 104 104
20 104 104 104 104 104 104 104
21 104 104 104 104 104 104 104
22 104 104 104 104 104 104 104
23 104 104 104 104 104 104 104
24 104 104 104 104 104 104 104
25 104 104 104 104 104 104 104
26 104 104 104 104 104 104 104
27 104 104 104 104 104 104 104
28 104 104 104 104 104 104 104
29 104 104 104 104 104 104 104
30 104 104 104 104 104 104 104
[*,*,3] : 1 2 3 4 5 6 7 :=
1 120 120 120 120 120 120 120
2 120 120 120 120 120 120 120
3 120 120 120 120 120 120 120
4 120 120 120 120 120 120 120
5 120 120 120 120 120 120 120
6 120 120 120 120 120 120 120
7 120 120 120 120 120 120 120
8 120 120 120 120 120 120 120
9 120 120 120 120 120 120 120
10 120 120 120 120 120 120 120
11 120 120 120 120 120 120 120
12 120 120 120 120 120 120 120
13 120 120 120 120 120 120 120
14 120 120 120 120 120 120 120
15 120 120 120 120 120 120 120
16 120 120 120 120 120 120 120
17 120 120 120 120 120 120 120
18 120 120 120 120 120 120 120
19 120 120 120 120 120 120 120
20 120 120 120 120 120 120 120
21 120 120 120 120 120 120 120
22 120 120 120 120 120 120 120
23 120 120 120 120 120 120 120
24 120 120 120 120 120 120 120
25 120 120 120 120 120 120 120
26 120 120 120 120 120 120 120
27 120 120 120 120 120 120 120
28 120 120 120 120 120 120 120
29 120 120 120 120 120 120 120
30 120 120 120 120 120 120 120;
Итак, сначала некоторые необычные вещи в определении вашей проблемы:
- Это не настоящая проблема оптимизации, так как ваша целевая функция фиксирована для каждого определения (в каждой смене 7 медсестер, и у каждой медсестры одинаковая цена за смену)
- В своей задаче вы определили 7 медсестер за смену, максимум 5 рабочих дней. Таким образом, вам нужно 7 медсестер в три смены за семь дней. Это равно 147 медсестрам / сменам. Но с ограничением в пять рабочих дней и только одной сменой в день у вас есть только 20 медсестер на 5 смен, что соответствует 100 медсестрам / сменам.
Я построил проблему в Mathprog, но код должен быть более или менее равен AMPL. Я начал с трех наборов для медсестер, дней и смен.
set shifts := {1,2,3};
set days := {1,2,3,4,5,6,7};
set nurses := {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
Расписание определяется как набор двоичных переменных:
var schedule{nurses, days, shifts}, binary;
Простая цель содержит сумму всех медсестер / смен в этой неделе с соответствующими ценами:
minimize cost: sum{i in nurses, j in days}(schedule[i,j,1]*c_morning+schedule[i,j,2]*c_day+schedule[i,j,3]*c_night);
К вашему первому ограничению можно ограничить сумму всех смен на одну медсестру пятью, поскольку возможна только одна смена в день:
s.t. working_days{n in nurses}:
sum{i in days, j in shifts}(schedule[n,i,j]) <= 5;
Выходной день - самая трудная часть проблемы. Для простоты я создал еще один набор, который содержит только дни, когда медсестра могла бы выполнить четыре ночные смены подряд. Вы также можете сформулировать ограничение с исходным набором дней и исключить первые четыре дня.
set nigth_days := {5,6,7};
s.t. rest{n in nurses,i in nigth_days}:
(schedule[n,i-4,3]+schedule[n,i-3,3]+schedule[n,i-2,3]+schedule[n,i-1,3]+sum{j in shifts}(schedule[n,i,j])) <= 4;
Из-за отсутствия утренней смены после ночной смены я использовал ту же попытку, что и в остальные дни. Седьмой день исключен, поскольку нет восьмого дня, когда мы могли бы искать утреннюю смену.
set yester_days := {1,2,3,4,5,6};
s.t. night_morning{i in yester_days, n in nurses}:
(schedule[n,i,3]+schedule[n,i+1,1]) <= 1;
Потребность в четырех медсестрах в смену должна быть удовлетворена (я сократил количество, так как более 4 медсестер недопустимы из-за ограничения в 5 смен)
s.t. demand_shift{i in days, j in shifts}:
sum{n in nurses}(schedule[n,i,j]) = 4;
Пятое ограничение - ограничить число смен в день максимум одним.
s.t. one_shift{n in nurses, i in days}:
sum{ j in shifts}(schedule[n,i,j]) <= 1;