Полный перебор
Полный перебор — это способ решения задачи, при котором алгоритм по очереди рассматривает все допустимые варианты, проверяет каждый по условию и сохраняет подходящие. Метод особенно полезен, когда число вариантов невелико и заранее можно точно оценить объём работы.
Идея полного перебора
Любая задача на перебор состоит из трёх частей: множества возможных вариантов, проверки допустимости или выполнения условия и выбора ответа среди прошедших проверку. Вариантом может быть число, слово, последовательность цифр, набор предметов, маршрут или набор значений переменных.
Полный перебор — алгоритм, который посещает каждый вариант из конечного множества допустимых вариантов и проверяет, удовлетворяет ли он условию задачи.
Если варианты строятся последовательно, удобно использовать дерево нұсқа. Его вершины соответствуют частично построенным вариантам, а ветви — возможным следующим действиям. Листья дерева — законченные варианты. Перебор идёт по всем листьям либо по всем значениям, которые задают варианты.
В задачах экзамена полный перебор часто выполняется двумя вложенными циклами, иногда — тремя или большим числом циклов. Важно заранее определить границы циклов и не пропустить ни одного значения. При этом следует различать перебор с повторениями и без повторений: например, числа 11 и 12 допустимы в первом случае, но не всегда во втором.
Математическая модель и оценка числа нұсқа
Пусть есть \(k\) позиций, а на каждую позицию можно независимо поставить один из \(n\) символов. Тогда количество последовательностей равно \(n^k\). Если на первой позиции \(n_1\) нұсқа, на второй \(n_2\) и так далее, общее число нұсқа находится правилом произведения.
Если выбираются \(k\) различных элементов из \(n\) без повторений и порядок важен, число нұсқа равно \(n(n-1)\ldots(n-k+1)\). Если порядок не важен, варианты считают иначе — это относится к перебору комбинаций. На практике сначала удобно оценить \(N\), а уже затем решать, допустим ли полный перебор по времени.
Чтобы не пропустить решения, нужно перебрать каждое значение каждой переменной в её допустимом диапазоне, а условие проверять после того, как построен полный кандидат. Если требуется максимум или минимум, сравнивают все подходящие кандидаты с текущим лучшим.
Для каждой проверки оценивают время жұмысы. Если нұсқа \(N\), а проверка бір нұсқа занимает \(O(1)\), то весь алгоритм имеет сложность \(O(N)\). Если проверка сама требует \(k\) действий, сложность становится \(O(Nk)\). Подробные способы сокращения такого поиска рассматриваются на странице сложность перебора с возвратом.
Сколько двузначных кодов можно получить, если каждая цифра выбирается независимо и может быть от 0 до 9?
Как построить алгоритм перебора
Удобный план шешімдер состоит из последовательных қадам.
- Определить, что именно является одним вариантом: число, пару чисел, слово или набор значений.
- Записать допустимые границы каждой переменной.
- Понять, допускаются ли повторения и важен ли порядок.
- Сформулировать точную проверку условия.
- Выбрать действие после успешной проверки: посчитать, вывести, найти максимум, минимум или сохранить вариант.
- Проверить граничные случаи: пустой набор, нулевые значения, одинаковые элементы и крайние границы циклов.
В простейшем случае перебор можно записать так: внешний цикл выбирает первое значение, внутренний — второе, а условие проверяется внутри тела внутреннего цикла. Если нужно найти количество решений, увеличивают счётчик. Если нужно найти наибольшее значение, хранят текущий максимум и обновляют его при нахождении лучшего кандидата.
answer := 0 for x from xmin to xmax: for y from ymin to ymax: if condition(x, y): answer := answer + 1
Сначала выпишите диапазоны переменных на бумаге и посчитайте число итераций. Это помогает заметить пропущенные значения и понять, не слишком ли велик перебор. Для вложенных циклов число итераций обычно равно произведению размеров диапазонов; см. подсчёт итераций вложенных циклов.
Разобранный пример
Найдём количество трёхзначных чисел \(abc\), составленных из цифр \(0,1,2,3,4\), в которых цифры не повторяются и число делится на 5. Первая цифра не может быть нулём. Число делится на 5 тогда и только тогда, когда последняя цифра равна 0 или 5. Цифры 5 среди разрешённых нет, значит последняя цифра обязана быть 0.
Перебираем сотни \(a\), десятки \(b\) и единицы \(c\). Ограничения: \(a\in\{1,2,3,4\}\), \(b,c\in\{0,1,2,3,4\}\), цифры различны, \(c=0\).
Полезно также записать программный перебор. Он повторяет рассуждение напрямую и особенно надёжен, когда условие становится сложнее.
1count = 0 2for a in range(1, 5): 3 for b in range(5): 4 for c in range(5): 5 if len({a, b, c}) == 3 and (100 * a + 10 * b + c) % 5 == 0: 6 count += 1 7print(count)
Программа перебирает \(4\cdot5\cdot5=100\) троек, но засчитывает только подходящие. Ответ равен 12. Вручную мы использовали свойство делимости и сократили перебор до подсчёта \(4\cdot3\).
Ошибки и проверка результата
1. Первая цифра числа допускается равной нулю. Для кода это возможно, для многозначного числа — нет. 2. Перепутаны границы: цикл от 1 до 10 обычно включает 10, а range(1, 10) в Python — нет. 3. Проверяется не весь вариант, а только часть переменных. 4. Условие «цифры различны» заменяют неполной проверкой. 5. При поиске максимума начальное значение берут неподходящим: например, 0, когда все допустимые ответы отрицательны.
Результат полезно проверять вторым способом: построить небольшую таблицу, вывести сами найденные варианты, решить задачу подсчётом или написать независимую реализацию. Если найдено количество вариантов, оно не должно превышать общего числа кандидатов.
Полный перебор не означает «перебирать хаотично». Сначала задают пространство вариантов, затем системно посещают каждый вариант ровно один раз и только после этого применяют условие.
Быстрая проверка
Главное
- Полный перебор системно проверяет все варианты конечного множества.
- Число нұсқа находят правилом произведения; при независимых позициях оно равно \(n_1\cdot n_2\cdot\ldots\cdot n_k\).
- Дерево возможных нұсқа показывает последовательность выборов и помогает не пропустить шешімдер.
- Для подсчёта используют счётчик, для оптимизации — текущие максимум или минимум.
- Перед запуском оценивают число итераций, внимательно задают границы и проверяют особые случаи.