Сменное расписание пролог компания 50 человек 30 дней минимум до выходных дней в неделю

У меня полусложная проблема планирования смены в прологе. Из того, что я видел, это можно решить с помощью CLF, но я не настолько хорошо знаком, и ресурсы в Интернете мне не очень помогли.

В задаче говорится, что в компании 50 сотрудников, и каждый сотрудник может работать либо в утреннюю смену (M), либо в вечернюю смену (E), в ночную смену (N), либо в день отдыха (R). Задача имеет 2 ограничения: не менее 15 сотрудников должны работать в утреннюю смену (M), 10 в вечернюю смену (E) и 8 в ночную смену (N), и что ни один сотрудник не может работать в ночную смену (N). и иметь утреннюю смену (M) на следующий день. Также в течение 7 дней у работника должно быть не менее 2 выходных, например, с 1 по 7 день, не менее двух R и столько же со 2 до 8.

Требуется создать 30-дневный график, удовлетворяющий вышеуказанным ограничениям и при наличии множества решений.

Какой может быть способ решить проблему и как я могу реализовать ее, используя код в прологе?

Большое спасибо!

Вот решение без последней задачи

days_in_month(30).
employees_num(50).


go :-
    days_in_month(Days),
    length(M, Days),
    days(M),
    show_days(M).


days([D1, D2|T]) :-
    two_days(D1, D2),
    (T = [] ; days([D2|T])).


other_day_constraints(D) :-
    day_constraint(10, e, D),
    maplist(rest_if_not_work, D).


day_constraint(Min, Element, Lst) :-
    employees_num(EmpsNum),
    list_has_ge_elements_being(Min, Element, EmpsNum, Lst).


two_days(D1, D2) :-
    % Set the full number of employees, otherwise prevent_double_shift can shorten the list
    employees_num(EmpsNum),
    length(D1, EmpsNum),
    length(D2, EmpsNum),

    % Pass the 2-day constraint first
    day_constraint(8, n, D1),
    prevent_double_shift(D1, D2),
    day_constraint(15, m, D2),
    
    % Remainder of the day constraints
    day_constraint(15, m, D1),
    day_constraint(8, n, D2),

    other_day_constraints(D1),
    other_day_constraints(D2).


prevent_double_shift([], []).
prevent_double_shift([H1|T1], [H2|T2]) :-
    (H1 == n -> dif (H2, m) ; true),
    prevent_double_shift(T1, T2).


rest_if_not_work(E) :-
    (var(E) -> E = r ; true).


show_days([]).
show_days([D|T]) :-
    show_day(D),
    show_days(T).


show_day(D) :-
    forall(member(E, D), (upcase_atom(E, U), write(U))),
    nl.


list_has_ge_elements_being(Min, Elem, MaxLen, L) :-
    list_has_ge_elements_being_(L, Min, Elem, MaxLen).

list_has_ge_elements_being_(L, Min, Elem, Min) :-
    !,
    length(L, Min),
    maplist(=(Elem), L).
list_has_ge_elements_being_(_L, 0, _Elem, _MaxLen).
list_has_ge_elements_being_([H|T], Min, Elem, MaxLen) :-
    Min @> 0,
    MaxLen @> Min,
    (   H = Elem,
        Min0 is Min - 1
    ;   Min0 = Min
    ),
    MaxLen0 is MaxLen - 1,
    list_has_ge_elements_being_(T, Min0, Elem, MaxLen0).

Просто для информации - этот код взят с сайта stackoverflow.com/a/70600935

brebs 17.01.2023 13:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот часть головоломки - я уверен, что вы можете понять остальное:

split_list_length_excl_rem(SegLen, L, Segs) :-
    length(L, Len),
    between(1, Len, SegLen),
    split_list_length_excl_rem_(SegLen, Len, L, Segs).

split_list_length_excl_rem_(SegLen, Len, L, Segs) :-
    (   Len @< SegLen
    ->  Segs = []
    ;   length(Seg, SegLen),
        split_list_length_excl_rem_seg_(Seg, L, R),
        Segs = [Seg|SegsT],
        Len0 is Len - SegLen,
        split_list_length_excl_rem_(SegLen, Len0, R, SegsT)
    ).

split_list_length_excl_rem_seg_([], R, R).
split_list_length_excl_rem_seg_([H|T], [H|LT], R) :-
    split_list_length_excl_rem_seg_(T, LT, R).

Результаты в swi-прологе:

?- numlist(1, 30, NL), split_list_length_excl_rem(7, NL, S).
NL = [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],
S = [[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]].

К сожалению, неправильно прочитал неделю, это более уместно:

sliding_segment(SegLen, L, Seg) :-
    length(L, Len),
    between(1, Len, SegLen),
    length(Seg, SegLen),
    sliding_segment_(L, Seg).

sliding_segment_([H|T], Seg) :-
    fill_list_copy(Seg, [H|T]).
sliding_segment_([_|T], Seg) :-
    sliding_segment_(T, Seg).

fill_list_copy([], _).
fill_list_copy([H|T], [H|R]) :-
    fill_list_copy(T, R).

Результаты в swi-прологе:

?- numlist(1, 30, NL), sliding_segment(7, NL, Seg).
Seg = [1, 2, 3, 4, 5, 6, 7] ;
Seg = [2, 3, 4, 5, 6, 7, 8] ;
Seg = [3, 4, 5, 6, 7, 8, 9] ;
...
Seg = [23, 24, 25, 26, 27, 28, 29] ;
Seg = [24, 25, 26, 27, 28, 29, 30] ;
false.

я могу понять, что ваш код разбивает список из 30 на весь возможный список из 7. Но я не могу понять, как я могу связать ваш код со своим, поэтому в прологе добавлено правило иметь как минимум 2 дня отдыха в период 7. Я Я могу понять, почему вы это сделали, но я просто не могу объединить эти коды для получения окончательного результата.

Θεοφανης Γιαννακοπουλος 19.01.2023 17:23

Подсказка: можно использовать forall или foreach, чтобы убедиться, что каждый 7-дневный сегмент содержит 2 дня отдыха. У вас уже есть list_has_ge_elements_being.

brebs 19.01.2023 17:46

Другие вопросы по теме