Шаг 38.
Задачи ComputerScience на Python.
Задачи поиска. Миссионеры и людоеды. Решение

    На этом шаге мы рассмотрим решение этой задачи.

    Теперь у нас есть все необходимое для решения задачи. Напомню: когда мы решаем задачу, используя функции поиска bfs(), dfs() и astar(), то получаем узел, который с помощью node_to_path() преобразуем в список состояний, приводящий к решению. Еще нам потребуется способ преобразовать этот список в понятную наглядную последовательность шагов для решения задачи о миссионерах и людоедах.

    Функция display_solution() преобразует путь решения в наглядный вывод - удобочитаемое решение задачи. Эта функция перебирает все состояния, вошедшие в готовый путь, а также отслеживает последнее состояние. Она анализирует разницу между последним состоянием и состоянием, которое отображается в настоящий момент, чтобы выяснить, сколько миссионеров и людоедов в каком направлении пересекло реку.

def display_solution(path: List[MCState]):
    if len(path) == 0:  # санитарная проверка
        return
    old_state: MCState = path[0]
    print(old_state)
    for current_state in path[1:]:
        if current_state.boat:
            print("{} миссионеров и {} людоедов переехали с восточного на западный берег.\n"
                  .format(old_state.em - current_state.em, old_state.ec - current_state.ec))
        else:
            print("{} миссионеров и {} людоедов переехали с западного на восточный берег.\n"
                  .format(old_state.wm - current_state.wm, old_state.wc - current_state.wc))
        print(current_state)
        old_state = current_state

    В функции display_solution() использовано преимущество, обусловленное тем, что MCState умеет вывести красивую сводку о своих данных с помощью __str__().

    Последнее, что нам остается сделать, - на самом деле решить задачу о миссионерах и каннибалах. Для этого удобно будет повторно задействовать функцию поиска, которую мы уже написали, потому что она является параметризованной. Здесь применяется bfs(), потому что использование dfs() потребовало бы пометить ссылочно разные состояния с одинаковым значением как равные, a astar() требует эвристики.

if __name__ == "__main__":
    start: MCState = MCState(MAX_NUM, MAX_NUM, True)
    solution: Optional[Node[MCState]] = bfs(start, MCState.goal_test, MCState.successors)
    if solution is None:
        print("Решение не найдено!")
    else:
        path: List[MCState] = node_to_path(solution)
        display_solution(path)
Архив с файлом можно взять здесь.

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

На западном берегу есть 3 миссионеров и 3 людоедов.
На восточном  берегу есть 0 миссионеров и 0 людоедов.
Лодка находится на западном берегу.
0 миссионеров и 2 людоедов переехали с западного на восточный берег.

На западном берегу есть 3 миссионеров и 1 людоедов.
На восточном  берегу есть 0 миссионеров и 2 людоедов.
Лодка находится на восточном берегу.
0 миссионеров и 1 людоедов переехали с восточного на западный берег.

На западном берегу есть 3 миссионеров и 2 людоедов.
На восточном  берегу есть 0 миссионеров и 1 людоедов.
Лодка находится на западном берегу.
0 миссионеров и 2 людоедов переехали с западного на восточный берег.

На западном берегу есть 3 миссионеров и 0 людоедов.
На восточном  берегу есть 0 миссионеров и 3 людоедов.
Лодка находится на восточном берегу.
0 миссионеров и 1 людоедов переехали с восточного на западный берег.

На западном берегу есть 3 миссионеров и 1 людоедов.
На восточном  берегу есть 0 миссионеров и 2 людоедов.
Лодка находится на западном берегу.
2 миссионеров и 0 людоедов переехали с западного на восточный берег.

На западном берегу есть 1 миссионеров и 1 людоедов.
На восточном  берегу есть 2 миссионеров и 2 людоедов.
Лодка находится на восточном берегу.
1 миссионеров и 1 людоедов переехали с восточного на западный берег.

На западном берегу есть 2 миссионеров и 2 людоедов.
На восточном  берегу есть 1 миссионеров и 1 людоедов.
Лодка находится на западном берегу.
2 миссионеров и 0 людоедов переехали с западного на восточный берег.

На западном берегу есть 0 миссионеров и 2 людоедов.
На восточном  берегу есть 3 миссионеров и 1 людоедов.
Лодка находится на восточном берегу.
0 миссионеров и 1 людоедов переехали с восточного на западный берег.

На западном берегу есть 0 миссионеров и 3 людоедов.
На восточном  берегу есть 3 миссионеров и 0 людоедов.
Лодка находится на западном берегу.
0 миссионеров и 2 людоедов переехали с западного на восточный берег.

На западном берегу есть 0 миссионеров и 1 людоедов.
На восточном  берегу есть 3 миссионеров и 2 людоедов.
Лодка находится на восточном берегу.
1 миссионеров и 0 людоедов переехали с восточного на западный берег.

На западном берегу есть 1 миссионеров и 1 людоедов.
На восточном  берегу есть 2 миссионеров и 2 людоедов.
Лодка находится на западном берегу.
1 миссионеров и 1 людоедов переехали с западного на восточный берег.

На западном берегу есть 0 миссионеров и 0 людоедов.
На восточном  берегу есть 3 миссионеров и 3 людоедов.
Лодка находится на восточном берегу.

    На следующем шаге мы подведем некоторые итоги.




Предыдущий шаг Содержание Следующий шаг