Разбор задачи: Красивая композиция

Предложенный нами код решения:

 def count_arrangement(n):
    # Функция для подсчета прекрасных перестановок
    def backtrack(index, used):
        # Если достигнут конец, найдено решение
        if index > n:
            return 1
        count = 0
        for num in range(1, n + 1):
            if not used[num] and (num % index == 0 or index % num == 0):
                used[num] = True
                count += backtrack(index + 1, used)
                used[num] = False
        return count

    # Используется для отслеживания занятых чисел
    used = [False] * (n + 1)
    return backtrack(1, used)

Рассмотрим решение задачи о подсчете "прекрасных перестановок" пошагово.


1. Определение функции

def count_arrangement(n):

Функция принимает целое число n — размер множества чисел от 1 до n, для которых требуется найти количество "прекрасных перестановок".


2. Вложенная функция для поиска перестановок

def backtrack(index, used):

Вложенная функция backtrack выполняет перебор перестановок.

  • index указывает текущую позицию в перестановке.
  • used — список, отслеживающий, какие числа уже заняты (True означает, что число используется).

3. Базовый случай

if index > n:
    return 1

Если текущая позиция index превышает n, это означает, что перестановка успешно сформирована, и её можно считать "прекрасной". В этом случае функция возвращает 1, добавляя к общему количеству найденных перестановок.


4. Перебор возможных чисел

for num in range(1, n + 1):

Этот цикл перебирает все числа от 1 до n. Каждое число num проверяется, можно ли его использовать на текущей позиции index.


5. Проверка условий

if not used[num] and (num % index == 0 or index % num == 0):

Число num можно использовать на позиции index, если оно:

  1. Ещё не занято (not used[num]).
  2. Удовлетворяет условию задачи:
    • num делится на index.
    • Либо index делится на num.

Если оба условия выполнены, мы можем продолжить с этим числом.


6. Пометка числа как используемого

used[num] = True
count += backtrack(index + 1, used)
used[num] = False
  • Число num помечается как занятое (True).
  • Рекурсивно вызывается backtrack для следующей позиции (index + 1).
  • После завершения текущего вызова число освобождается (False), чтобы его можно было использовать в других перестановках.

7. Возврат итогового значения

return count

Счётчик count аккумулирует количество "прекрасных перестановок", найденных для текущей ветки рекурсии.


8. Инициализация и запуск рекурсии

used = [False] * (n + 1)
return backtrack(1, used)

Список used создаётся с размером n + 1 (индексация начинается с 1). Все элементы инициализируются как False, так как на старте ни одно число не используется.
Рекурсия запускается с начальной позиции index = 1.


Пример работы

Для n = 2:

  1. index = 1, перебираются числа {1, 2}:
    • Для num = 1, условие выполнено. Рекурсия продолжается с index = 2.
    • Для num = 2, условие выполнено. Рекурсия продолжается с index = 2.
  2. index = 2, перебираются оставшиеся числа:
    • Для первого вызова (num = 1), остаётся num = 2, и условие выполнено.
    • Для второго вызова (num = 2), остаётся num = 1, и условие выполнено.

Итог: 2 перестановки.

 



Вы должны Войти или Зарегистрироваться чтобы оставлять комментарии