Форум программистов, компьютерный форум, киберфорум
Prolog
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/58: Рейтинг темы: голосов - 58, средняя оценка - 4.81
Alenkakiss
1

Поиск в ширину (миссионеры и людоеды) на SWI-Prolog

27.12.2009, 13:46. Показов 10782. Ответов 7
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Помогите новичку разобраться в логической задаче.
Условие
Миссионеры и людоеды (поиск в ширину).
Три миссионера и три людоеда находятся по одну сторону реки, через которую они хотят переправиться. В их распоряжении имеется лодка, которая может выдержать вес только двух человек. Кроме того, если в какой-то мо-мент число людоедов станет больше числа миссионеров, миссионеры будут съедены независимо от того, на каком берегу реки это случится.
Указания к решению. Различные состояния этой задачи однозначно задаются информацией, на каком берегу находятся лодка и сколько миссионеров и лю-доедов на этом же берегу.
Поэтому структура
state(ЛокализацияЛодки,
ЧислоМиссионеровНаТомБерегуГдеЛодка,
ЧислоЛюдоедовНаТомБерегуГдеЛодка)
полностью описывает состояние. Допустимые состояния для решения задачи - это те, когда людоеды не могут съесть миссионеров ни на том берегу, где лодка, ни на противоположном,
Возможные значение первого аргумента: атомы west (западный берег) и east (восточный берег). Возможные значения остальных аргументов: 0, 1, 2 или 3.
Начальное состояние: state(east,3, 3). Конечное состояние: state(west,3,3).

2 людоеда или 1 людоед и 1 миссионер переправляются.
2. миссионер возвращается назад, если посылали 2 людоедов, то возвращается один из людоедов.
Итак: на 1-ом берегу 2Л и 3М, на втором 1Л.
3. Посылаем на тот берег 2Л.
4. Возвращаем 1Л.
Итак: на 1-ом берегу 1Л и 3М, на втором 2Л.
5. Пускаем 2М на тот берег.
6. Возвращаем 1Л и 1М.
Итак: На этом берегу 2Л и 2М, на втором 1Л и 1М
7. Посылаем на тот берег 2М.
8. Возвращаем на 1-ый берег 1Л.
Итак: на 1-ом берегу 3Л, на втором 3М.
9. Посылаем на тот берег 2Л.
10. Возвращаем назад 1Л.
11. Переправляем последних голодных и уставших 2Л.


Нашла решение этой задачи на VIP7 с помощью поиска в ширину. Оно содержит 11 переправ.
Prolog
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
open core, console, list
 
domains
сост = tuple(symbol, integer*, integer*).
путь = сост*.
 
class predicates
поиск_в_ширину: (сост, сост) -> путь determ.
поиск_в_ширину: (путь*, сост*, сост) -> путь determ.
переход: (сост) -> сост nondeterm.
перевезти: (integer, integer*, integer*, integer*, integer*) nondeterm (i,i,i,o,o). 
 
clauses
поиск_в_ширину(X, Y) = поиск_в_ширину([[X]], [X], Y).
 
поиск_в_ширину([[Y | П] | _], _, Y) = [Y | П]:- !.
поиск_в_ширину([[X | П] | Пути], Состояния, Y) = поиск_в_ширину(НовПути, Состояния1, Y):-
    Продолжения = [[Z, X| П] || Z = переход(X), not(isMember(Z, Состояния))],
            НовПути = append(Пути, Продолжения),
            Вершины = [V || [V | _] = getMember_nd(Продолжения)],
            Состояния1 = append(Вершины, Состояния).
 
переход(tuple("л", Л, П)) = tuple("п", Л1, П1):-
    N = std::fromTo(1, 2),
    перевезти(N, Л, П, Л1, П1).
переход(tuple("п", Л, П)) = tuple("л", Л1, П1):-
    N = std::fromTo(1, 2),
    перевезти(N, П, Л, П1, Л1).        
 
перевезти(N, [КДо, МДо], [КПосле, МПосле], [КДо-КЛ, МДо-МЛ], [КПосле+КЛ, МПосле+МЛ]):- 
    КЛ = std::fromTo(0, КДо),
    КЛ <= N, 
    МЛ = N - КЛ,
    МЛ <= МДо,  
    if МДо-МЛ > 0 then КДо-КЛ <= МДо-МЛ end if,
    if МПосле+МЛ > 0 then КПосле+КЛ <= МПосле+МЛ end if.
 
class facts
    счетчик : positive := 0.
 
clauses
    run():- 
        init(),
        Старт = tuple("л", [3, 3], [0, 0]),  
        Цель= tuple("п", [0, 0], [3, 3]), 
        Путь = поиск_в_ширину(Старт, Цель), 
        foreach tuple(Берег, Левый, Правый) = getMember_nd(reverse(Путь)),
                Левый = [КЛ, МЛ], Правый = [КП, МП]
          do 
            writef("%. На левом берегу: % кан. и % мис.; на правом берегу: % кан. и % мис. \n", 
                   счетчик, КЛ, МЛ, КП, МП),
            if Берег = "л" 
               then write("\tлодка отправляется с левого берега на правый\n\n")
               else if not(Левый = [0, 0]) then 
                      write("\tлодка отправляется с правого берега на левый\n\n") end if
             end if,
             счетчик := счетчик + 1
        end foreach,
        !, 
        _ = readLine();
        succeed().
Подскажите, как переделать для SWI-Prolog?
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
27.12.2009, 13:46
Ответы с готовыми решениями:

Поиск в глубину или ширину (SWI Prolog)
Помогите решить задачу! Найти все пути из Москвы в Новосибирск, проходящие через Пермь. Нужно...

"Миссионеры и людоеды", prolog 5.2
Здравствуйте уважаемые профессионалы,помогите пожалуйста исправить ошибку в коде,что-то у меня не...

Миссионеры и людоеды
Помогите разобраться в логической задаче. Условие. Миссионеры и людоеды. Три миссионера и три...

Поиск в базе данных SWI-Prolog
Добрый вечер! Прошу помощи по SWI-Prolog(-у). Нужно реализовать в базе данных поиск, который будет...

7
92 / 92 / 6
Регистрация: 04.05.2011
Сообщений: 171
31.05.2011, 18:35 2
Легче написать всё заново.
Prolog
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
% Константы: [0,0,0]-финиш, [1,3,3]- начало.
go(List,Out):- 
    findall(X,theEnd(List,X),Out), 
    not(Out=[]), !.
go(List,Out):- 
    findall(X,move(List,X),Xl), !, 
    go(Xl,Out).
theEnd(List,[[1,3,3]|A]):- 
    member([[1,3,3]|A],List).
move(List,[[C,Mn,Kn],[A,M,K]|W]):- 
    member([[A,M,K]|W],List), 
    C is 1-A, Z is C-A, d(Dm,Dk), Mn is M+Z*Dm,
    Mn>=0, 3>=Mn, Kn is K+Z*Dk, Kn>=0, 3>=Kn, 
    check(Mn,Kn), not(member([C,Mn,Kn],W)).
 
d(1,0). 
d(2,0). 
d(1,1). 
d(0,1). 
d(0,2).
 
check(M,K):- M=\=0, K>M ,!,fail.
check(M,K):- M=\=3, 3-K>3-M, !,fail.
check(_,_). 
 
member(A,[A|_]).
member(A,[_|B]):- member(A,B).
 
?-go([[[0,0,0]]],X),write(X).
2
2507 / 1483 / 37
Регистрация: 14.09.2009
Сообщений: 2,740
31.05.2011, 20:08 3
emppu2007,
Ведь специально тема создавалась Поиск в пространстве состояний (поиск по графам тоже сюда!).
PS
И зачем member определять, он же встроенный?
0
92 / 92 / 6
Регистрация: 04.05.2011
Сообщений: 171
31.05.2011, 21:12 4
Тогда почему эта тема на форуме валяется уже полтора года и никто её не удалил?
Мне модератор rrrFer сказал, что лучше находить всякие старые интересные темы на форуме без ответов и отвечать на них. Я и решил этим немного заняться.
Извините уж, что испортил вашу вечеринку и создаю, якобы, бардак на форуме.
Ага.
0
2507 / 1483 / 37
Регистрация: 14.09.2009
Сообщений: 2,740
31.05.2011, 21:22 5
Так ни я, ни rrrFer тогда еще и модераторами то не были. И уж тем более не было той закрепленной темы. А в старом мусоре копаться как-то у меня времени нет, создали бы такую сейчас - точно бы удалила.
0
0 / 0 / 0
Регистрация: 05.03.2012
Сообщений: 4
03.05.2012, 01:40 6
Кто нибудь может помочь с такой модификацией? На левом берегу реки находятся N миссионеров и N людоедов. Есть лодка, в которую можно посадить P пассажиров (P< 2N). Необходимо найти последовательность действий для перевозки всех на правый берег реки таким образом, чтобы в лодке и на любом из берегов миссионеров всегда было больше, чем людоедов. Спасибо!
0
2507 / 1483 / 37
Регистрация: 14.09.2009
Сообщений: 2,740
03.05.2012, 17:26 7
Наработки пожалуйста. Хотя бы самостоятельно N впихните. Т.е надо будет передавать еще один параметр, и все 3 заменить на N.
0
0 / 0 / 0
Регистрация: 26.11.2009
Сообщений: 9
14.12.2012, 11:19 8
"Миссионеры и людоеды". Поиск в ширину.
Три миссионера и три людоеда находятся по одну сторону реки, через которую они хотят переправиться. В их распоряжении имеется лодка, которая может выдержать вес только двух человек. Кроме того, если в какой-то момент число людоедов станет больше числа миссионеров, миссионеры будут съедены независимо от того, на каком берегу реки это случится.
Указания к решению. Различные состояния этой задачи однозначно задаются информацией, на каком берегу находятся лодка и сколько миссионеров и людоедов на этом же берегу.
Поэтому структура
state(ЛокализацияЛодки,ЧислоМиссионеровНаТомБерегу ГдеЛодка, ЧислоЛюдоедовНаТомБерегуГдеЛодка)
полностью описывает состояние. Допустимые состояния для решения задачи - это те, когда людоеды не могут съесть миссионеров ни на том берегу, где лодка, ни на противоположном,
Возможные значение первого аргумента: атомы west (западный берег) и east (восточный берег). Возможные значения остальных аргументов: 0, 1, 2 или 3.
Начальное состояние: state(east,3, 3). Конечное состояние: state(west,3,3).

Добавлено через 35 минут
как ее решить на swi prologe?
0
14.12.2012, 11:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.12.2012, 11:19
Помогаю со студенческими работами здесь

Поиск подстроки в строке на SWI-Prolog
Добрый вечер. Помогите написать программу, которая будет отвечать на вопрос: &quot;Содержится ли...

SWI-prolog. Поиск по заданому критерию
Появлются ошибки при запуске, но не пойму, что не так, в каком месте ошибка. . Warning:...

swi prolog, поиск факториала, вывод результата
Здравствуйте. Надо написать программу, которая будет искать факториал числа N. Собственно,...

SWI-Prolog поиск конечных звеньев ломаной
Помогите написать программу для ... поиска конечных звеньев ломаной, проблема в том, что надо...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru