Кузнецов, Токарев, Слесарев и Резчиков играют в домино

Главная Форумы Программирование Помощь с решением задач на Prolog Решение головоломок на Prolog Кузнецов, Токарев, Слесарев и Резчиков играют в домино

В этой теме 3 ответа, 2 участника, последнее обновление  Васильев Владимир Сергеевич 2 года/лет, 10 мес. назад.

  • Автор
    Сообщения
  • #1761

    questioner
    Участник

    Помогите решить логическую задачу:

    Четыре человека играют в домино.
    Их фамилии Кузнецов, Токарев, Слесарев и Резчиков.
    Профессия каждого игрока соответствует фамилии одного из других игроков.
    Напротив Кузнецова сидит слесарь.
    Напротив Резчикова сидит резчик.
    Справа от Слесарева сидит токарь.
    Кто сидит слева от кузнеца?

    Мой вариант решения:

    naprotiv(A,B,[_,A,_,B]).
    naprotiv(B,A,[A,_,B,_]).
    naprotiv(B,A,[_,A,_,B]).
      
    sprava(A,B,[A,B,_,_]).
    sprava(A,B,[_,_,A,B]).
      
    sleva(A,B,L):-
      sprava(B,A,L).
      
    insert(Y,XZ,XYZ):-
      append(X,Z,XZ),append(X,[Y],XY),append(XY,Z,XYZ).
      
    permute([],[]).
    permute([H|Tail],P):-
      permute(Tail,T),insert(H,T,P).
      
    find(Ans):-
      permute([kuznecov,tokarev,slesarev,rezchikov],[A,B,C,D]),
      permute([kuznec,tokar,slesar,rezchik],[Q1,Q2,Q3,Q4]),
      L=[m(A,Q1),m(B,Q2),m(C,Q3),m(D,Q4)],
      member(m(S1,kuznec),L),not(S1=kuznecov),
      member(m(S2,tokar),L),not(S2=tokarev),
      member(m(S3,slesar),L),not(S3=slesarev),
      member(m(S4,rezchik),L),
      Surnames=[A,B,C,D],
      naprotiv(kuznecov,S3,Surnames),
      sprava(slesarev,S2,Surnames),
      naprotiv(rezchikov,S4,Surnames),
      sleva(Ans,S1,Surnames).

    Мне не понятно что прога делает (я пытаюсь отладить ее по шагам в графическом виде, но мне это ничего не дает). Можете помочь с комментариями если вам не трудно? В прологе новичок,а задача нужна очень сильно.
    Статью про решение логических задач прочитал – не помогло.

  • #1762

    С комментариями помогу если будут конкретные вопросы.
    Если коротко, то функция find:

    • перебирает все варианты фамилий и профессий в разных порядках;
    • помещает полученный вариант (набор профессий и фамилий) в список (так удобней обрабатывать);
    • проверяет чтобы профессии кузнеца, токаря и слесаря не совпадали с соответствующей фамилией;
    • строка следит за тем, чтобы напротив S3 (а S3 — это слесарь) сидит Кузнецов;
    • #1763

      questioner
      Участник

      Я лишь мельком прочитал вашу статью и осознал, что мой случай не тривиален (дальше не читал).
      Конкретные вопросы:

      • сперва вызывается
        permute([kuznecov,tokarev,slesarev,rezchikov],[A,B,C,D])
        Это предикат, который имеет входной список (состоящий из фамилий) и выходной(A,B,C,D).
        Затем он рекурсивно помещается сюда permute([],[]), а затем попадает в
        permute([H|Tail],P):-permute(Tail,T),insert(H,T,P).

        где permute([H|Tail],P) разделяет список на голову и хвост, в P будет помещен результат.
        permute(Tail,T) обходит рекурсивно по всему списку (до тех пор, пока в списке не останется 1 значение – в данном случае Резчиков).
        Затем, передаем нашего Резчикова в предикат insert(H,T,P) — где H хранит Резчикова, T и P пустые параметры.

      • совсем не понятно что происходит дальше:

        append([],B,B).
        append([H|Tail],B,[H|NewTail]):-
          append(B,Tail,NewTail).
         
        member(H,[H|_]).
        member(H,[_|Tail]):-
          member(H,Tail).
         
        naprotiv(A,B,[_,A,_,B]).
        naprotiv(B,A,[A,_,B,_]).
        naprotiv(B,A,[_,A,_,B]).
         
        sprava(A,B,[A,B,_,_]).
        sprava(A,B,[_,_,A,B]).
         
        sleva(A,B,L):-sprava(B,A,L).
         
        insert(Y,XZ,XYZ):-
          append(X,Z,XZ),append(X,[Y],XY),append(XY,Z,XYZ).

      • Почему member(m(S4,rezchik),L) не имеет такой же конструкции как и предыдущие правила?

      Предположу что из за все возможных перестановок, при присвоении фамилии резчику(фамилия Резчиков будет уже соответствовать какой то из профессий?).

      • #1764

        Задача тривиальна и решается по шаблону (в статье есть 2 похожих переборных задачи). Часть не понятным Вам предикатов уже описаны на блоге с комментариями к каждой строчке. Я не буду повторять это для каждой задачи. Пользуйтесь поиском. Предикаты append, member являются стандартными. Вместо permute можно использовать стандартный permutation.
        Предикат insert тоже не нужен, я бы использовал вместо него стандартный предикат flatten (он тоже описан на блоге).

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

Для ответа в этой теме необходимо авторизоваться.