Considere um problema de programação da enfermeira para o departamento de um hospital específico. Todos os dias, há três turnos de 12 horas, começando em 7h, 13h e 19h. A o horizonte de planejamento é de quatro dias, começando em 01/05/2023, para um total de 12 turnos. Há quatro enfermeiros registrados que podem ser atribuídos a esses turnos, com o de ter dois enfermeiros no departamento ao mesmo tempo. Cobertura requisito obrigatório.
todos os enfermeiros precisam descansar entre os turnos por pelo menos 12 horas (720 minutos); e pode funcionar no máximo 36 horas (2.160 minutos) durante o horizonte de planejamento especificado. Essas restrições têm prioridade alta e média, respectivamente.
Diversos turnos por dia
Três turnos por dia são representados como três turnos independentes. Por exemplo: turnos para o primeiro dia (de quatro dias) no "departamento" local são representadas como:
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
},
...
]
}
Exemplo com 12 turnos (quatro dias com três turnos por dia)
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}]
}
Descansar entre turnos
Para representar o restante entre os turnos de um funcionário, use o
minimumRestMinutes
de um
restrição de programação. Os horários de início e término dos
a restrição são usadas para determinar quais mudanças devem ser consideradas e,
precisam estar alinhadas com um horizonte de planejamento, sobrepondo todas as mudanças. A
o tempo de descanso é especificado em minutos (720) e a prioridade é PRIORITY_HIGH
conforme
acima. A primeira enfermeira (chamada Adam), é representada como:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}]
}
}
Tempo máximo de trabalho
A quantidade máxima de tempo que um funcionário pode trabalhar também é representada por uma
restrição de programação, usando maximumMinutes
. O tempo máximo de trabalho neste exemplo é de 2.160 minutos. O início e o
os horários de término da restrição devem estar alinhados com todo o horizonte de planejamento. A
representação correspondente do primeiro enfermeiro (Adam) pode ser atualizada para:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}
}
Exemplo com os quatro funcionários
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}]
}
Cobertura para enfermeiros registrados
A cobertura de dois enfermeiros registrados a qualquer momento é representada por um
requisito de cobertura. Especificamente,
roleRequirements
foi preenchido com um
requisito de função para o qual roleId
está definido.
"Registered Nurse", targetEmployeeCount
é definido como 2 e priority
é definido como
PRIORITY_MANDATORY
. Os horários de início e término do requisito de cobertura precisam
se sobreponham a cada turno. O campo locationId
está definido como "department" para que
apenas as mudanças ocorridas nesse local são consideradas.
{
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Exemplo de solicitação completa
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}],
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}],
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Exemplo de resposta
A resposta do solucionador contém a atribuição das enfermeiras aos turnos e a status do procedimento de otimização. Por exemplo, os turnos atribuídos primeiro funcionário são retornadas como:
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
... ]
}
Exemplo de resposta completa
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
}
]
}