【问题标题】:Prolog company/employee scheduling problemProlog公司/员工调度问题
【发布时间】:2022-01-04 19:18:48
【问题描述】:

我在 prolog 中有一个半复杂的轮班调度问题。 据我所知,它可以用 CLF 解决,但我不是很熟悉,网上的资源并没有真正帮助我。

问题说明公司有 50 名员工,每个员工既可以上早班(M),也可以上晚班(E)、夜班(N)或休息日(R)。 该问题有 2 个限制条件:至少有 15 名员工必须在早班工作(M),10 必须在晚班工作(E) 和 8 晚上一个 (N) 并且没有员工可以上夜班 (N) 和早班 (M) 次日。

它要求通过满足上述限制来产生一个 30 天的时间表,并且存在多种解决方案。

有什么方法可以解决这个问题,我如何使用 prolog 中的代码来实现它?

非常感谢!

【问题讨论】:

  • 家庭作业?如果没有,请不要使用 Prolog。使用 or-tools 或类似的东西。如是?嗯......你尝试了什么? Prolog 中有什么可用的?显然,有一个相当简单的与 SAT 兼容的合取范式公式。能否很好地扩展取决于 基数 的表达方式。
  • 是的,这确实是功课。我试图思考如何解决这个问题,但我们所做的并没有真正涵盖如此复杂的主题。我似乎找不到如何找到解决方案...有什么想法吗?
  • 首先尝试在 Prolog 中做一个声明性的幼稚解决方案,看看这是否足够好(它可能是)。如果您需要在互联网上搜索,这些通常称为“生成和测试”或“蛮力”。
  • 哪些在线资源对您没有帮助

标签: algorithm prolog


【解决方案1】:

这是一个完整的解决方案(使用 swi-prolog):

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.


% Potentially use E as the first element
list_length_abs(N, E, [E|_]) :-
    N > 1.
list_length_abs(0, _, []).
list_length_abs(1, E, [E]).


list_has_ge_elements_being(0, _E, MaxLen, L) :-
    !,
    MaxLen >= 0,
    % Don't need E
    list_length_abs(MaxLen, _, L).

list_has_ge_elements_being(Min, E, MaxLen, [H|T]) :-
    must_be(integer, MaxLen),
    MaxLen >= 1,
    must_be(integer, Min),
    Min >= 1,
    Min =< MaxLen,
    list_has_ge_elements_being_(Min, E, MaxLen, [H|T]).

list_has_ge_elements_being_(Min, E, MaxLen, L) :-
    Min =:= MaxLen ->
        length(L, Min),
        maplist(=(E), L)
    ; MaxLen =:= 1 ->
        list_has_ge_elements_being_maxlen1_(Min, L, E)
    ;   list_has_ge_elements_being_flex_(Min, E, MaxLen, L).


list_has_ge_elements_being_maxlen1_(0, [_], _).
list_has_ge_elements_being_maxlen1_(1, [E], E).

list_has_ge_elements_being_flex_(Min, H, MaxLen, [H|T]) :-
    % Loop while unifying the element
    succ(Min0, Min),
    succ(MaxLen0, MaxLen),
    % Check whether can terminate the list early
    (Min0 =:= 0 -> true ; list_has_ge_elements_being_(Min0, H, MaxLen0, T)).

list_has_ge_elements_being_flex_(Min, E, MaxLen, [H|T]) :-
    % Ensure that the element is not already the intended value
    \+ E == H,
    succ(MaxLen0, MaxLen),
    list_has_ge_elements_being_(Min, E, MaxLen0, T).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    相关资源
    最近更新 更多