Рубрики
Без рубрики

Алгоритмическое мышление с Python Part 2 – Снижение и завоевание Стратегия

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

Автор оригинала: Robin Andrews.

Эта статья о вычислительном мышлении. Перед тем, как мы погрузимся, проверьте эту головоломку:

Пазла парила пазла

Отряд 20 солдат должен пересечь реку без моста. Есть два мальчика, играя в маленьком на берегу. Лодка достаточно большая, чтобы нести одного солдата или два мальчика.

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

Вы можете попробовать эту головоломку для себя в аксессуаре ниже. Я дам решение позже в этой статье.

Снижение и завоевание проблемы решения проблемы

Снижение и завоевание Это методика решения вычислительной проблемы, которая принимает проблему и уменьшает ее в меньшую проблему, которая легче решить. Иногда это путают с Разделить и завоевать Что похоже, но что разбивает проблему в несколько небольших проблем. Для сравнения Сортировка слияния и QuickSort являются примерами деления и завоевания алгоритмов.

Классические примеры Снижение и завоевание находятся:

  • Бинарный поиск
  • Алгоритм Евклида
  • Глубинный поиск
  • Широк-первый поиск
  • Сортировка и выбор вставки

Например, в Бинарный поиск Пространство поиска уменьшается в 2 раза на каждом этапе, что привело к очень эффективному алгоритму (с временной сложностью o (log n) ). В случае алгоритма Евклида для нахождения наибольшего общего делителя двух целых чисел большее число делится на более меньший на каждом этапе, и алгоритм повторяется с использованием меньшего количества и оставшейся части предыдущего подразделения. Для вставки сортировка размер несортируемого раздела данных уменьшается на каждом шаге.

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

На каждом этапе алгоритма проблема сводится к меньшей версии той же проблемы, пока не будет найдено решение (или не быть возможным).

Категории для количества снижения являются:

Снижение постоянной

Это часто с постоянной.

Примеры:

  • Сортировка вставки
  • Графические алгоритмы поиска: DFS, BFS

Снижение постоянным фактором

Чаще всего в два раза, как в двоичных поисках

Примеры:

  • Бинарный поиск
  • Фальшивые монеты
  • «Русское крестьянское умножение»

Уменьшение переменного размера

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

Решение для пазлов пазла пазла

И теперь на тот момент, когда вы все ждали, решение для пазлов пазлов пазла пазла пазла.

Во-первых, два мальчика должны грести лодок на другую сторону, после чего один из них возвращается с лодкой. Затем один солдат строгает лодку на другую сторону и остается там, пока другой мальчик возвращает лодку. Эти четыре поездки уменьшают размер задачи на 1 (описанные количеством солдат, нуждающихся в пересечении реки). Таким образом, если эта четырехлетняя процедура повторяется в общей сложности 20 раз, проблема будет решена после общего количества 80 поездок Отказ Для общего экземпляра N солдат, 4n Поездки должны быть сделаны.

Как ты это сделал? Вы получили тот же результат?

Пазл пазла пазла пазла Предоставляет отличную иллюстрацию Снижение и завоевание стратегии для решения вычислительных проблем.

Питонский листинг для пазлов пазла пазла

"""
Ferrying Soldiers Puzzle Python Implmentation
Robin Andrews - https://compucademy.net/
"""
import os
import time

NUM_SOLDIERS = 2

def section_break():
    print("*" * 50)


def print_rules():
    pass


def print_state(state, moves_taken):
    os.system("cls" or "clear")
    left_bank, right_bank, bank = state["left_bank"], state["right_bank"], state["bank"]
    print("#### CURRENT STATE OF PUZZLE ####\n")
    print(f"Moves taken: {moves_taken}\n")
    # print(f"{left_bank} | {right_bank}\n")
    print(f"{left_bank['boys']} boys, {left_bank['soldiers']} soldiers | {right_bank['boys']} boys, {right_bank['soldiers']} soldiers\n")
    print(f"Boat is on {bank} bank")


def get_move(state):
    print("\nPuzzle options: \n")
    print("1. Ferry both boys from left to right bank")
    print("2. Ferry both boys from right to left bank")
    print("3. Ferry one boy from left to right bank")
    print("4. Ferry one boy from right to left bank")
    print("5. Ferry a soldier from left to right bank")
    print("6. Ferry a soldier from right to left bank\n")
    choice = 0
    while choice not in [1, 2, 3, 4, 5, 6]:
        try:
            choice = int(input("Choose an action(1-4): "))
        except:
            continue

    return choice


def process_move(move, state, moves_taken):
    # We can allow 1 boy, 2 boys or one soldier to cross only
    bank = state["bank"]
    legal_move = False
    # Move both boys from left to right bank
    if move == 1 and bank == "left":
        if state["left_bank"]["boys"] == 2:
            state["left_bank"]["boys"] -= 2
            state["right_bank"]["boys"] += 2
            legal_move = True
            state["bank"] = "right"
    elif move == 2 and bank == "right":
        if state["right_bank"]["boys"] == 2:
            state["right_bank"]["boys"] -= 2
            state["left_bank"]["boys"] += 2
            legal_move = True
            state["bank"] = "left"
    elif move == 3 and bank == "left":
        if state["left_bank"]["boys"] > 0:
            state["left_bank"]["boys"] -= 1
            state["right_bank"]["boys"] += 1
            legal_move = True
            state["bank"] = "right"
    elif move == 4 and bank == "right":
        if state["right_bank"]["boys"] > 0:
            state["right_bank"]["boys"] -= 1
            state["left_bank"]["boys"] += 1
            legal_move = True
            state["bank"] = "left"
    elif move == 5 and bank == "left":
        if state["left_bank"]["soldiers"] > 0:
            state["left_bank"]["soldiers"] -= 1
            state["right_bank"]["soldiers"] += 1
            legal_move = True
            state["bank"] = "right"
    elif move == 6 and bank == "right":
        if state["right_bank"]["soldiers"] > 0:
            state["right_bank"]["soldiers"] -= 1
            state["left_bank"]["soldiers"] += 1
            legal_move = True
            state["bank"] = "left"

    if legal_move:
        moves_taken +=1
        return state, moves_taken
    else:
        print("That move is not possible at this time.")
        time.sleep(1)
        return state, moves_taken


def is_win(state):
    return state == {"left_bank": {"boys": 2, "soldiers": 0},
             "right_bank": {"boys": 0, "soldiers": NUM_SOLDIERS},
             "bank": "left"}


def main():
    state = {"left_bank": {"boys": 2, "soldiers": NUM_SOLDIERS},
             "right_bank": {"boys": 0, "soldiers": 0},
             "bank": "left"}
    moves_taken = 0
    while not is_win(state):
        # section_break()
        print_state(state, moves_taken)
        move = get_move(state)
        state, moves_taken = process_move(move, state, moves_taken)  # maybe modify moves_taken in main()

    print(f"Well done - you solved the puzzle! You took {moves_taken} moves.")


main()

Для справки, вот Python 3 Версия парила парила пазла

Счастливые вычисления!