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

23.02 Количество программ из A в B (на убывание)

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

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

Задача 1#26075

Исполнитель преобразует число, записанное на экране. У исполнителя есть три команды, которым присвоены номера:

  1. Вычесть 1  ;
  2. Вычесть 3  ;
  3. Разделить нацело на 3  .

При выполнении команды 3  выполняется деление нацело (остаток отбрасывается). Программа для исполнителя — это последовательность команд. Сколько существует таких программ, которые исходное число 22  преобразуют в число 2  ?

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

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

Идея решения с помощью рекурсии состоит в создании функции f(a, b), которая считает количество программ, преобразующих число a  в число b  . На каждом шаге проверяются следующие условия:

- Если a  равно b  , то найден корректный путь и функция возвращает 1;

- Если a  стало меньше b  , то путь невозможен и возвращается 0;

- Если ни одно из условий не выполнено, функция вызывает саму себя трижды, моделируя каждую из команд: a-1 (вычесть 1), a-3 (вычесть 3) и a//3 (целочисленное деление на 3). Сумма этих трёх вызовов даёт общее количество программ для текущего значения a  .

Таким образом, при вызове f(22, 2) функция рекурсивно перебирает все допустимые последовательности команд, подсчитывая количество способов достичь числа 2.

# Определяем рекурсивную функцию f(a, b) для подсчета программ
def f(a, b):
    # Если текущее число равно целевому числу,
    # то найден один корректный путь, возвращаем 1
    if a == b:
        return 1
    # Если текущее число меньше целевого,
    # дальнейшие преобразования невозможны, возвращаем 0
    if a < b:
        return 0
    # В остальных случаях считаем все возможные варианты:
    # 1) вычесть 1
    # 2) вычесть 3
    # 3) разделить нацело на 3
    # Суммируем количество программ из каждого варианта
    return f(a - 1, b) + f(a - 3, b) + f(a // 3, b)

# Запускаем функцию для исходного числа 22 и целевого числа 2
print(f(22, 2))

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

Динамический способ решения основывается на обратном построении массива, где индекс i  соответствует числу на экране, а значение в ячейке a[i]  — количество способов из исходного числа 22 дойти до числа i  .

- Сначала создаём массив, заполненный нулями, длиной достаточной для хранения всех промежуточных значений, например, 70 элементов; - В ячейку с индексом 22 записываем 1, так как начинаем с числа 22 и существует ровно один способ быть в этом положении; - Затем проходим в цикле от 21 до 2 включительно, и для каждого числа i  вычисляем количество программ, суммируя:

   - a[i+ 1]  — количество программ, которые придут к i  через команду "вычесть 1";

   - a[i+ 3]  — количество программ, которые придут к i  через команду "вычесть 3";

   - a[i∗3]  , a[i∗3 + 1]  , a[i∗3 + 2]  — количество программ, которые придут к i  через команду "разделить нацело на 3 учитывая, что при делении нацело все числа i∗ 3  , i∗ 3+ 1  , i∗ 3+ 2  дают в результате i  .

После заполнения всех ячеек, значение a[2]  будет содержать общее количество программ, которые преобразуют число 22 в число 2.

# Создаем массив из 70 элементов, все значения изначально равны 0
a = [0] * 70
# Начальное число 22 имеет ровно один способ быть в позиции
a[22] = 1
# Перебираем все числа от 21 до 2 включительно в обратном порядке
for i in range(21, 1, -1):
    # Считаем количество программ для числа i,
    # суммируя варианты, которые приведут к i:
    # 1) из i+1 командой "вычесть 1"
    # 2) из i+3 командой "вычесть 3"
    # 3) из i*3, i*3+1, i*3+2 командой "разделить нацело на 3"
    a[i] = a[i + 1] + a[i + 3] + a[i * 3] + a[i * 3 + 1] + a[i * 3 + 2]

# Выводим количество программ, преобразующих 22 в 2
print(a[2])

Ответ: 2196

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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