"Информатика (базовый и углублённый уровень)", Гейн А.Г., Сенокосов А.И.
Поиск в ширину — способ обходить граф от выбранной вершины, сначала посещая ближайших соседей, а затем всё более удалённые вершины. Он нужен, чтобы проверить достижимость, найти минимальное число рёбер до каждой вершины и восстановить кратчайший маршрут в невзвешенном графе. Алгоритм использует очередь и отметки посещения: благодаря им вершины обрабатываются по уровням и не рассматриваются повторно.
Текст подготовлен нейронной сетью по теме параграфа и не заменяет учебник — важные факты и формулировки сверяйте с ним.
Поиск в ширину — алгоритм обхода графа, который посещает вершины послойно: сначала ближайшие к стартовой, затем более удалённые. Граф состоит из вершин и соединяющих их рёбер, а стартовая вершина задаёт точку начала поиска. Такой порядок нужен, когда требуется узнать, какие вершины достижимы и сколько шагов до них.
Очередь — структура данных, в которую элементы добавляют в конец, а извлекают из начала, то есть по принципу «первым пришёл — первым вышел». В поиске в ширину в неё помещают обнаруженные вершины. Очередь помогает не перепрыгивать через целый уровень и сохранять порядок обработки.
Расстояние в рёбрах — минимальное число рёбер на пути от стартовой вершины до выбранной. Например, если до вершины можно добраться по двум рёбрам, её расстояние равно 2. Это понятие позволяет сравнивать пути по числу переходов и записывать уровень каждой вершины.
Массив посещённых вершин хранит отметку о том, была ли вершина обнаружена алгоритмом. Как только вершина впервые найдена, её помечают посещённой. Такая отметка нужна, чтобы циклы графа не заставляли алгоритм ходить по кругу и добавлять одну вершину в очередь несколько раз.
Поиск начинают со стартовой вершины, потому что расстояния и порядок обхода определяются относительно неё. Ей присваивают расстояние 0: до неё самой не нужно проходить ни одного ребра. Затем рассматривают её соседей, то есть вершины, соединённые с ней одним ребром, и получают первый слой с расстоянием 1. После него алгоритм переходит к вершинам, до которых нужно пройти два ребра, затем три и так далее.
Чтобы уровни обрабатывались по порядку, используют очередь. Старт помещают в неё первой; извлекая вершину, алгоритм рассматривает её соседей и добавляет в очередь тех, кого ещё не обнаруживал. Новые вершины оказываются в конце, за уже ожидающими обработки вершинами предыдущего слоя. Поэтому все вершины на меньшем расстоянии успевают обработаться раньше вершин на большем расстоянии.
Отметку посещения ставят при добавлении вершины в очередь, а не при её извлечении. Между этими действиями соседние вершины могут встретить её снова; без отметки они добавят её повторно. Это создаёт лишнюю работу, а также может усложнить правильный учёт расстояний и предков. Если же пометить вершину сразу, алгоритм рассматривает её только один раз.
При просмотре каждого ребра алгоритм проверяет, обнаружен ли его второй конец. Если нет, этот конец впервые найден из текущей вершины: ему задают расстояние, равное расстоянию текущей вершины плюс 1, сохраняют предка и ставят в очередь. В невзвешенном графе все переходы имеют одинаковую длину, поэтому первый найденный путь содержит минимальное число рёбер. Позднее найти путь с меньшим числом рёбер уже невозможно: очередь обрабатывает более близкие уровни раньше.
Если нужна только достижимость цели, поиск можно остановить, когда цель впервые обнаружена: известны и сам факт достижимости, и минимальное расстояние до неё. Чтобы получить расстояния до всех доступных вершин, очередь обрабатывают до опустошения. Для восстановления маршрута дополнительно сохраняют предка каждой вершины. Если граф несвязный, один запуск охватывает только компоненту старта, поэтому для полного обхода запускают поиск из каждой ещё не посещённой вершины.
| Элемент алгоритма | Назначение | Момент изменения | Результат |
|---|---|---|---|
| Стартовая вершина | Задаёт начало обхода | До запуска поиска | От неё отсчитываются расстояния |
| Очередь | Хранит вершины, ожидающие обработки | При обнаружении добавляют в конец, при обработке извлекают из начала | Обход по уровням |
| Массив посещённых вершин | Не даёт обрабатывать вершины повторно | При первом обнаружении вершины | Каждая вершина добавляется в очередь не более одного раза |
| Массив расстояний | Хранит число рёбер от старта | При первом обнаружении вершины | Минимальные расстояния в невзвешенном графе |
| Массив предков | Запоминает, откуда впервые пришли в вершину | При первом обнаружении вершины | Возможность восстановить маршрут |
| Условие завершения | Определяет, когда прекратить обход | Когда очередь опустела или найдена цель | Обход компоненты или ответ для заданной цели |
Таблица помогает понять, какие данные нужны для конкретной задачи: для проверки достижимости достаточно отметок посещения, а для расстояний нужен соответствующий массив. Если требуется вывести маршрут, заранее добавьте массив предков. Выберите условие остановки по вопросу задачи: найти одну цель или обработать всю достижимую часть графа.
Условие. Неориентированный граф задан списками соседей: A соединена с B и C, B — с A и D, C — с A и D и E, D — с B и C, E — с C. Стартовая вершина — A. Требуется записать порядок посещения и расстояние каждой вершины от старта. Соседей будем просматривать в указанном порядке.
Ответ. Порядок посещения: A, B, C, D, E. Расстояния: A — 0, B — 1, C — 1, D — 2, E — 2. При другом порядке просмотра соседей порядок внутри одного уровня может измениться, но минимальные расстояния останутся теми же.
Условие. В невзвешенном графе нужно найти кратчайшее расстояние от вершины S до всех остальных вершин. Список смежности позволяет просматривать только рёбра, выходящие из текущей вершины. Требуется также отличить недостижимые вершины от тех, для которых путь существует.
Ответ. Запускаем поиск в ширину, присваивая каждой новой вершине расстояние текущей плюс 1. Массив расстояний после завершения поиска содержит кратчайшие расстояния в рёбрах до всех достижимых вершин, а отметка −1 указывает на недостижимость.
Условие. Помещения представлены вершинами, проходы — рёбрами графа. Нужно найти маршрут из A в E с минимальным числом проходов и вывести последовательность помещений. Достаточно считать все проходы равными по длине, а порядок соседей при просмотре задавать заранее.
Ответ. Массив расстояний даёт длину кратчайшего маршрута, а массив предков — его последовательность. В примере восстановленный маршрут A, C, E содержит два прохода; проверка соседних пар подтверждает, что каждый шаг соответствует ребру графа.
Если отмечать вершину посещённой только после извлечения, несколько соседей могут добавить её в очередь одновременно. Так часто поступают, путая обнаружение вершины с её обработкой, но это вызывает дублирование работы. Помечайте вершину сразу при добавлении и проверьте, что каждую вершину очередь получает не более одного раза.
Замена очереди стеком меняет порядок извлечения: последняя добавленная вершина обрабатывается первой. Так происходит поиск в глубину, который может уйти далеко по одной ветви прежде, чем рассмотреть ближайших соседей. Проверьте структуру и порядок операций: для поиска в ширину добавление должно идти в конец, а извлечение — из начала.
В графе с весами первый найденный маршрут не обязательно самый дешёвый. Ошибка возникает, когда минимальное число рёбер принимают за минимальную сумму длин или стоимости. Перед применением BFS проверьте, равны ли веса; при разных весах сравнивайте именно стоимость путей и выбирайте подходящий алгоритм.
Запуск из одной вершины не охватывает вершины, до которых нет пути из старта. Ученик может принять пустые или неизвестные значения за недоработку алгоритма, хотя граф может быть несвязным. После обхода проверьте массив посещений: если остались непосещённые вершины, запустите поиск из одной из них и повторяйте, пока все не будут обработаны.
Для работы с поиском в ширину нужно уметь представлять граф вершинами и рёбрами, читать список смежности и пользоваться циклами. Очередь и массивы — базовые структуры данных, которые позволяют организовать порядок обхода и хранить результаты. Эти знания помогают самостоятельно проследить изменение состояния алгоритма.
Поиск в ширину применяют для проверки достижимости и нахождения кратчайших путей в невзвешенных графах. Похожий принцип уровней используют в задачах о распространении сигнала, заражения или движения по клеткам, где каждый переход считается одним шагом. Полученные расстояния показывают, на каком шаге процесс достигнет каждой вершины.
Сравнение с поиском в глубину помогает увидеть, как выбор очереди или стека меняет обход одного и того же графа. Массив предков связывает поиск с восстановлением маршрутов и другими алгоритмами на графах. Для взвешенных графов нужны методы, которые учитывают стоимость рёбер, а не только их количество.
Почему для поиска в ширину нужна именно очередь?
Очередь извлекает вершины в порядке их добавления. Поэтому сначала алгоритм обрабатывает все вершины текущего расстояния, а затем переходит к следующему уровню. Если использовать стек, порядок изменится и получится поиск в глубину.
Когда вершину нужно отмечать посещённой?
Вершину отмечают в момент первого обнаружения, сразу перед добавлением в очередь. Так соседние вершины не смогут добавить её повторно. Первое обнаружение в поиске в ширину происходит по кратчайшему числу рёбер.
Найдёт ли поиск в ширину кратчайший путь в графе с весами?
Не всегда: поиск в ширину минимизирует количество рёбер, но не сумму их весов. Если веса различаются, более короткий по числу рёбер маршрут может оказаться дороже. Для таких задач применяют другие алгоритмы, например алгоритм Дейкстры при неотрицательных весах.
Как восстановить сам маршрут, а не только его длину?
При первом обнаружении каждой вершины нужно сохранить её предка — вершину, из которой мы в неё перешли. Затем от цели переходят к предку, пока не дойдут до старта. Полученную последовательность разворачивают: это и будет маршрут от старта к цели.
Как обойти весь граф, если он несвязный?
Запустите поиск из одной непосещённой вершины, чтобы обойти её компоненту связности. Затем найдите другую непосещённую вершину и запустите поиск снова. Повторяйте, пока непосещённых вершин не останется.
Лабораторная работа № 23 (к § 53) Поиск в ширину