код планирования не определяет все решения. возможно, нет возврата? - PullRequest
0 голосов
/ 07 мая 2020

У меня проблема с расписанием, когда я хочу, чтобы все клиенты получали один из трех слотов. Есть ровно три слота, которые можно заполнить. Вот мой код на данный момент.

get_taken_times(Schedule, Times):-
get_taken_times(Schedule, [], Times).
get_taken_times([], Times, Times).    
get_taken_times([C-T|CustomerTimes], TimeAccum, Times) :- 
    get_taken_times(CustomerTimes, [T | TimeAccum], Times).  


schedule(Customers, Schedule):-
schedule(Customers, PartialSchedule, Schedule).
schedule([], Schedule, Schedule).
schedule([Customer-[Time|Times]|CustomerTimes], PartialSchedule, Schedule):- 
(   get_taken_times(PartialSchedule, TakenTimes),
    \+ member(Time, TakenTimes)) -> 
        schedule(CustomerTimes, [Customer-Time | PartialSchedule], Schedule);
schedule([Customer-Times|CustomerTimes], PartialSchedule, Schedule).    

Если он запускается как тест

schedule([a-[1,2,3], b-[1,2,3], c-[1,2,3]], Schedule)

Я получаю этот результат, и это нормально

[c-3,b-2,a-1]

Но Я не понимаю, почему не находят остальные пять возможных решений (всего должно быть шесть). Предположительно, есть проблема с возвратом, но я не понимаю, где? Не мог бы кто-нибудь объяснить, как это можно изменить, чтобы найти все шесть решений?

1 Ответ

2 голосов
/ 08 мая 2020

Прежде всего, как также отмечено в комментарии, всегда проверяйте одиночные предупреждения , а всегда исправляйте их, прежде чем пытаться что-либо еще. Системы Prolog выдают эти предупреждения не для развлечения! Они выдают их, потому что они часто указывают на серьезные ошибки в вашей программе. В этом конкретном случае, если я оставлю в ваших одиночных файлах, но в остальном применим свое исправление ниже, ваша программа будет вести себя следующим образом:

?- schedule([a-[1,2,3], b-[1,2,3], c-[1,2,3]], Schedule).
Schedule = [c-3, b-2, a-1] ;
Schedule = [c-2, b-3, a-1] ;
Schedule = [c-3, b-1, a-2] ;
Schedule = [c-1, b-3, a-2] ;
Schedule = [c-2, b-1, a-3] ;
Schedule = [c-1, b-2, a-3] ;
ERROR: Out of global stack

Теперь давайте рассмотрим проблему с возвратом. Помимо решения с a-1 вы также можете попробовать решения с a-2 и a-3. Но в момент, когда вы рассматриваете термин времени клиента a-[1, 2, 3], у вас есть Customer = a, Time = 1, Times = [2, 3] и TakenTimes = []. 1 не является членом []. Вы только когда-либо пробуете альтернативное время, если рассматриваемое в настоящее время Time является членом TakenTimes, но поскольку TakenTimes является [], и ничто не является его членом. Таким образом, вы никогда не будете пробовать альтернативное время для a.

Проблема заключается в ручной рекурсии по доступному клиенту времени. Вы эффективно реализуете своего рода «оптимизацию», когда рассматриваете только одно решение, а не все возможные. Чтобы получить все возможные, вам необходимо перечислить (не повторять!) Все доступное время клиента. Примерно так:

schedule([], Schedule, Schedule).
schedule([Customer-AvailableTimes|CustomerTimes], PartialSchedule, Schedule):- 
    get_taken_times(PartialSchedule, TakenTimes),
    member(Time, AvailableTimes),
    \+ member(Time, TakenTimes),
    schedule(CustomerTimes, [Customer-Time | PartialSchedule], Schedule).

Для данного списка TakenTimes это пробует все разрешенные альтернативные времена для клиента. И, если вы исправите свои проблемы с синглтоном, это даст вам все решения, а затем красиво завершится:

?- schedule([a-[1,2,3], b-[1,2,3], c-[1,2,3]], Schedule).
Schedule = [c-3, b-2, a-1] ;
Schedule = [c-2, b-3, a-1] ;
Schedule = [c-3, b-1, a-2] ;
Schedule = [c-1, b-3, a-2] ;
Schedule = [c-2, b-1, a-3] ;
Schedule = [c-1, b-2, a-3] ;
false.

Еще одно примечание по вашей реализации get_taken_times/2: это правда, что часто вам нужен аргумент аккумулятора для выполнения интересные вещи в списках. Но здесь это совсем не нужно, и ваше решение даже не такое общее, как могло бы быть:

?- get_taken_times(Xs, [1, 2, 3]).
Xs = [_2686-3, _2704-2, _2722-1] ;
ERROR: Out of global stack

Скорее, при связывании списков, где заголовки списков находятся в некотором отношении, мы обычно express это прямо в заголовке предложения. Примерно так:

get_taken_times([], []).
get_taken_times([_Customer-Time | CustomerTimes], [Time | Times]) :-
    get_taken_times(CustomerTimes, Times).

Это ведет себя более логично:

?- get_taken_times(Xs, [1, 2, 3]).
Xs = [_2046-1, _2058-2, _2070-3].

Лучшим именем для этого предиката было бы что-то вроде pairs_seconds/2 или, возможно, pairs_values/2. Он присутствует в библиотеке SWI-Prolog под последним именем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...