Задача №23 КИМ: Подсчет программ для исполнителя с запрещенной траекторией
Исполнитель выполняет преобразование числа на экране с помощью двух команд:
- Команда 1: Прибавить 1.
- Команда 2: Умножить на 2.
Программа для исполнителя представляет собой последовательность таких команд. Необходимо определить, сколько существует программ, которые преобразуют исходное число 1 в число 30, при условии, что траектория вычислений не проходит через число 10.
Предложенные решения и их анализ
Рассмотрим два программных подхода к решению задачи.
Подход 1: Раздельный расчет (ошибочный)
Идея: разбить задачу на две независимые части - подсчет путей от 1 до 9 и от 11 до 30, тем самым «перепрыгнув» запрещенную точку 10.
def f(st, end):
a={st: 1}
for i in range(st + 1, end + 1):
a[i]=0
if i - 1 in a:
a[i]+=a[i - 1]
if i % 2 == 0 and int(i//2) in a:
a[i]+=a[int(i//2)]
return a[end]
print(f(1,9)*f(11,30))Почему этот подход неверен? Он не учитывает все возможные траектории. Умножение количества путей из первого отрезка на количество путей из второго предполагает, что любой путь до 9 можно скомбинировать с любым путем от 11. Однако это не так: для перехода от 9 к 11 требуется как минимум две команды (например, +1 и +1), и не все пути от 9 заканчиваются в состоянии, из которого возможен переход в 11, минуя 10. Метод игнорирует необходимость непрерывности траектории между отрезками, что приводит к подсчету несуществующих комбинаций.
Подход 2: Единый расчет с исключением запрещенной точки (корректный)
Идея: вести динамический подсчет путей для всех чисел от 1 до 30, но явно обнулить количество способов попасть в запрещенную точку 10. Это гарантирует, что ни одна траектория, проходящая через 10, не будет учтена в итоговом результате для числа 30.
def f(st, end, propusk):
a={st: 1}
for i in range(st + 1, end + 1):
a[i]=0
a[propusk]=0 # Явное обнуление путей в запрещенную точку
if i - 1 in a:
a[i]+=a[i - 1]
if i % 2 == 0 and int(i//2) in a:
a[i]+=a[int(i//2)]
return a[end]
print(f(1,30, 10))Почему этот подход корректен? Алгоритм моделирует все возможные переходы. Присваивая a[10] = 0 на каждом шаге, мы гарантируем, что количество способов попасть в число 10 всегда равно нулю. Следовательно, в количество путей для любого последующего числа (включая 30) не войдут те траектории, которые в какой-то момент проходили через запрещенную точку. Это соответствует точному условию задачи.
Ключевой вывод
Первый код ошибочен, потому что задача требует подсчета непрерывных траекторий от начальной до конечной точки. Простое перемножение количества путей в двух непересекающихся отрезках нарушает эту непрерывность и учитывает комбинации, которые не являются валидными программами для исполнителя. Корректное решение должно рассматривать весь путь как единое целое, явно исключая запрещенные состояния из процесса вычислений.