Тема 23. Оператор присваивания и ветвления

23.08 Прочие прототипы

Вспоминай формулы по каждой теме
Решай новые задачи каждый день
Вдумчиво разбирай решения
ШКОЛКОВО.
Готовиться с нами - ЛЕГКО!
Подтемы раздела оператор присваивания и ветвления
Решаем задачу:

Ошибка.
Попробуйте повторить позже

Задача 1#30493

Исполнитель Щелчок находится на первой ступеньке очень длинной лестницы. У исполнителя есть 3 команды:

1. Подняться на одну ступеньку и потратить одну единицу энергии.

2. Перешагнуть через одну ступеньку (подняться на две) и потратить 3 единицы энергии

3. Перешагнуть через две ступеньки (подняться на 3 ступеньки) и потратить 6 единиц энергии

Программа для исполнителя — это последовательность команд.

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

Показать ответ и решение

Решение рекурсией

Идея рекурсивного решения заключается в построении функции f(st, fn, en, comand), которая рассматривает все возможные последовательности команд для достижения цели и одновременно отслеживает оставшуюся энергию и количество сделанных ходов.

1. Мы создаем функцию с аргументами:

- st — текущая ступенька, на которой находится исполнитель;

- fn — целевая ступенька, на которую нужно попасть (в нашем случае 25);

- en — количество оставшейся энергии;

- comand — количество использованных команд.

2. Внутри функции выполняются следующие проверки:

- Если st == fn и энергия en >= 0, значит мы достигли цели:

- Если текущее количество команд меньше глобального минимального, обновляем минимальное количество команд и сохраняем текущую энергию.

- Если текущее количество команд равно глобальному минимальному и энергия больше сохранённой, обновляем максимальную энергию.

- Возвращаемся из функции, так как дальнейшие шаги не нужны.

- Если en < 0, то дальнейшие шаги невозможны, функция также завершает выполнение.

3. Если ни одно из условий не выполнено, мы рекурсивно вызываем функцию для всех трёх команд:

- Подняться на одну ступеньку и потратить 1 единицу энергии (f(st + 1, fn, en - 1, comand + 1));

- Подняться на две ступеньки и потратить 3 единицы энергии (f(st + 2, fn, en - 3, comand + 1));

- Подняться на три ступеньки и потратить 6 единиц энергии (f(st + 3, fn, en - 6, comand + 1)).

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

5. Изначально глобальные переменные:

- count — большое число для минимизации команд,

- ener — минимально возможная энергия, которую будем обновлять при нахождении лучших решений.

6. Запускаем функцию с начальными параметрами: первая ступенька, целевая 25-я, 60 единиц энергии и 0 команд. После завершения рекурсии выводим найденные значения минимального числа команд и максимальной энергии.

# Импортируем кэширование для ускорения рекурсии
from functools import lru_cache

# Создаем функцию f с аргументами: текущая ступенька st, конечная fn, энергия en, количество команд comand
@lru_cache(None)
def f(st, fn, en, comand):
    # Если достигли цели и энергия не отрицательна
    global count, ener
    if st == fn and en >= 0:
        # Если текущее количество команд меньше минимального
        if comand < count:
            count = comand
            ener = en
        # Если количество команд совпадает, выбираем максимум энергии
        elif comand == count and en > ener:
            ener = en
        # Завершаем текущий путь
        return
    # Если энергии недостаточно для дальнейших шагов
    if en < 0:
        return
    # Пробуем все три возможные команды и рекурсивно считаем результаты
    f(st + 1, fn, en - 1, comand + 1)
    f(st + 2, fn, en - 3, comand + 1)
    f(st + 3, fn, en - 6, comand + 1)

# Инициализация глобальных переменных
count = 10000000  # минимальное количество команд
ener = -1         # максимальная энергия для минимального количества команд

# Запускаем рекурсивную функцию с начальной позиции
f(1, 25, 60, 0)

# Выводим найденные минимальное количество команд и максимальную оставшуюся энергию
print(count, ener)

Решение динамикой

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

1. Создаем список ans и помещаем туда начальное состояние: первая ступенька, 60 единиц энергии, 0 команд.

2. В цикле перебираем возможные шаги до тех пор, пока есть новые состояния: - Для каждого состояния проверяем: - Если текущая ступенька больше 25 или энергия отрицательна — игнорируем это состояние. - Если достигнута 25-я ступенька и энергия неотрицательна: - Если количество команд равно текущему минимальному, обновляем максимальную энергию. - Если количество команд меньше минимального, обновляем минимальное количество команд и сохраняем энергию. - Для остальных состояний добавляем новые возможные ходы: - Подняться на 1 ступеньку и потратить 1 единицу энергии. - Подняться на 2 ступеньки и потратить 3 единицы энергии. - Подняться на 3 ступеньки и потратить 6 единиц энергии.

3. После обработки всех состояний нового уровня копируем их в ans для следующей итерации.

4. Цикл продолжается до тех пор, пока возможные новые ходы существуют. В конце выводим минимальное количество команд и максимальную энергию, которые были найдены.

# Инициализация списка достижимых состояний
ans = []
ans.append((1, 60, 0))  # (текущая ступенька, энергия, количество команд)

# Инициализация переменных для хранения ответа
otv, mn_com = -100000000, 100000000

# Цикл по возможным уровням ходов
for operations in range(1000):
    can_get = []
    for i in ans:
        step, energy, go = i
        # Пропускаем недопустимые состояния
        if (step > 25) or (energy < 0):
            continue
        # Если достигли цели
        if (step == 25) and (energy >= 0):
            if mn_com == go:  # одинаковое минимальное количество команд
                mn_com = go
                otv = max(otv, energy)
                continue
            elif mn_com > go:  # нашли меньшее количество команд
                mn_com = go
                otv = energy
                continue
        # Добавляем все возможные ходы
        can_get.append((step + 1, energy - 1, go + 1))
        can_get.append((step + 2, energy - 3, go + 1))
        can_get.append((step + 3, energy - 6, go + 1))
    # Если новых ходов нет, выходим из цикла
    if len(can_get) == 0:
        break
    ans = can_get.copy()

# Выводим минимальное количество команд и максимальную сохранённую энергию
print(mn_com, otv)

Ответ: 8 12

Специальные программы

Все специальные программы

Программа
лояльности v2.0

Приглашай друзей в Школково и получай вознаграждение до 10%!

Крути рулетку
и выигрывай призы!

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

Бесплатное онлайн-обучение

Для школьников из приграничных территорий России, проживающих в ДНР, ЛНР, Херсонской, Запорожской, Белгородской, Курской, Брянской областях и Крыму.

Налоговые вычеты

Узнай, как получить налоговый вычет при оплате обучения в «Школково».

Специальное предложение
для учителей

Бесплатный доступ к любому курсу подготовки к ЕГЭ, ОГЭ и олимпиадам от «Школково». Мы с вами делаем общее и важное дело, а потому для нас очень значимо быть чем-то полезными для учителей по всей России!

Вернём деньги за курс
за твою сотку на ЕГЭ

Сдать экзамен на сотку и получить обратно деньги за подготовку теперь вполне реально!

cyberpunkMouse
cyberpunkMouse
Рулетка
Вы можете получить скидку в рулетке!