На Горох
Информатика, 11 класс

§ 53. Алгоритмы обхода связного графа

"Информатика (базовый и углублённый уровень)", Гейн А.Г., Сенокосов А.И.

Объяснение темы В оглавлении: § 53. Алгоритмы обхода связного графа

Кратко о теме

Обход графа — способ последовательно исследовать его вершины, не обрабатывая одну и ту же вершину снова. Он помогает проверить, какие вершины достижимы, найти путь и исследовать структуру сети. Два основных способа обхода — поиск в глубину и поиск в ширину. В первом случае алгоритм продвигается по одному пути, во втором — рассматривает вершины слоями, начиная с ближайших к исходной. Для полного обхода связного графа оба способа посещают все его вершины.

Объяснение темы

Текст подготовлен нейронной сетью по теме параграфа и не заменяет учебник — важные факты и формулировки сверяйте с ним.

Определения и обозначения

Связный граф — граф, в котором из любой вершины можно попасть в любую другую по рёбрам. Значит, между любой парой вершин есть путь. Это свойство позволяет начать обход с одной вершины и в итоге добраться до всех остальных.

Обход графа — последовательное посещение его вершин по заданным правилам с отметкой уже посещённых вершин. Отметку обычно хранят в виде списка или множества. Она помогает алгоритму понимать, какие вершины уже обработаны.

Поиск в глубину — обход, при котором из текущей вершины переходят к ещё не посещённому соседу и продолжают идти как можно дальше. Если продолжать путь нельзя, алгоритм возвращается к предыдущей вершине. Такой способ удобен, когда нужно исследовать направления графа одно за другим.

Поиск в ширину — обход, при котором сначала посещают соседей исходной вершины, затем соседей этих вершин и так далее. Вершины рассматриваются по уровням удалённости от начала. Поэтому этот способ полезен для поиска кратчайших путей в невзвешенном графе.

Как это устроено

Посещённые вершины отмечают, потому что в графе могут быть циклы: из одной вершины можно пройти по рёбрам и вернуться в неё же. Без отметок алгоритм не отличит уже обработанную вершину от новой и может повторять одни и те же действия. Кроме того, одну вершину часто обнаруживают из нескольких соседних. Отметка предотвращает и бесконечный обход, и лишние повторные обработки.

Обход начинается с выбора исходной вершины. Её сразу помечают посещённой, затем рассматривают её соседей — вершины, соединённые с ней ребром. Правило выбора следующего соседа зависит от способа обхода и принятого порядка перебора. Пометка при обнаружении важна: тогда один и тот же сосед не будет несколько раз добавлен в структуру данных.

Поиск в глубину можно реализовать с помощью стека — структуры, где последним добавляют и первым извлекают элемент, — или рекурсии, то есть вызова алгоритмом самого себя. Каждый переход к новому соседу продолжает текущую ветвь, поэтому обход углубляется. Когда продолжать некуда, алгоритм возвращается к вершине, из которой пришёл, и проверяет другие варианты. Так постепенно исследуются все ветви, достижимые из начала.

Поиск в ширину использует очередь: в ней первым извлекают элемент, который добавили раньше. Обнаруженных соседей помещают в конец очереди, а следующую вершину берут из её начала. Благодаря такому порядку сначала обрабатываются вершины на расстоянии одного ребра от исходной, затем на расстоянии двух и далее. Если расстоянием считать число рёбер, первый найденный путь до вершины будет кратчайшим.

Порядок обхода может меняться, если по-разному перебирать соседей одной вершины. Например, сначала можно рассматривать вершину B, а можно C; тогда изменится последовательность посещений. Однако в связном графе полный обход не пропускает вершины, поскольку от исходной вершины существует путь к каждой. При правильной отметке каждую вершину обрабатывают ровно один раз, хотя порядок этой обработки не обязан быть единственным.

Сравнение поиска в глубину и поиска в ширину

Сравнивайте алгоритмы по тому, как они выбирают следующую вершину и какую структуру данных используют. Это помогает не путать их даже в графе, где оба обхода в итоге посещают одни и те же вершины. Для поиска кратчайшего пути в невзвешенном графе особенно важен порядок обработки BFS.

ХарактеристикаПоиск в глубинуПоиск в ширину
Основной принципУглубляется по одному путиОбходит вершины по уровням
Используемая структура данныхСтек или рекурсияОчередь
Порядок посещения вершинСначала дальние вершины выбранной ветвиСначала ближайшие к исходной вершине
Что происходит, если новых соседей нетВозврат к предыдущей вершинеИзвлечение следующей вершины из очереди
Для каких задач особенно удобенИсследование структуры графа и его ветвейПоиск кратчайшего пути по числу рёбер

Разбор задач

Для первых двух задач возьмём один и тот же связный граф со списками соседей: A — B, C; B — A, D, E; C — A, F; D — B; E — B, F; F — C, E. Соседей рассматриваем в алфавитном порядке. Это условие нужно, чтобы у примера был однозначный порядок обхода. Исходная вершина — A.

Задача 1. Выписать порядок обхода в глубину. Здесь нужно идти к первому доступному непосещённому соседу, а не выбирать вершину, которая кажется ближе к началу. Когда путь закончится, возвращаемся назад и ищем следующий выход. Записываем вершину только при первом обнаружении.

  1. Отмечаем A. Её первый непосещённый сосед — B, поэтому переходим к B.
  2. У B первым доступен D. У D новых соседей нет, значит, возвращаемся к B; следующий непосещённый сосед B — E.
  3. От E переходим к F, затем от F — к C. У C и A новых соседей нет, поэтому обход завершается после возврата по пройденному пути.

Ответ: A, B, D, E, F, C. Вершины D и C оказываются в разных частях последовательности, потому что глубина выбирает одну ветвь до конца, прежде чем вернуться к другой.

Задача 2. Выписать порядок обхода в ширину и очередь после обработки каждой вершины. Помещаем A в очередь и отмечаем её. Обнаруженных непосещённых соседей добавляем в конец очереди по алфавиту, а уже обнаруженные вершины повторно не добавляем.

  1. Извлекаем A, добавляем B и C. Очередь: B, C.
  2. Извлекаем B, добавляем D и E. Очередь: C, D, E.
  3. Извлекаем C, добавляем F. Очередь: D, E, F.
  4. Извлекаем D, новых вершин нет. Очередь: E, F.
  5. Извлекаем E, сосед F уже обнаружен. Очередь: F; затем извлекаем F, новых вершин нет. Очередь становится пустой.

Ответ: порядок посещения — A, B, C, D, E, F. Очередь каждый раз сохраняет обнаруженные, но ещё не обработанные вершины, поэтому сначала заканчивается уровень соседей A, а затем рассматривается следующий уровень.

Задача 3. Найти кратчайшее расстояние от A до каждой вершины и путь до F. Запускаем поиск в ширину, задаём расстояние до A равным 0, а её предшественника оставляем пустым. Когда впервые обнаруживаем соседа вершины, записываем расстояние на единицу больше и сохраняем вершину, из которой пришли.

  1. Из A обнаруживаем B и C: расстояние до каждой равно 1, предшественник — A.
  2. Из B впервые обнаруживаем D и E: расстояние до них равно 2, предшественник — B.
  3. Из C впервые обнаруживаем F: расстояние до F равно 2, предшественник — C. Позже найденный путь через E будет длиннее и запись не меняет.
  4. Восстанавливаем маршрут от F по предшественникам: F, C, A. Разворачиваем последовательность, чтобы получить путь от начала.

Ответ: расстояния: A — 0, B — 1, C — 1, D — 2, E — 2, F — 2. Кратчайший путь от A до F: A — C — F, его длина равна двум рёбрам.

Типичные ошибки

Не отмечать вершину при обнаружении. Тогда её могут несколько раз добавить в очередь или стек, особенно если соседи соединены циклом. Ошибку допускают, откладывая пометку до обработки вершины. Проверка: помечайте вершину сразу, когда впервые добавляете её для дальнейшей обработки.

Считать порядок обхода единственным. При нескольких соседях можно выбрать их в разной последовательности, поэтому изменится и весь маршрут алгоритма. Часто путают один возможный результат с единственно верным. Проверяйте, задан ли порядок перебора соседей, и указывайте его при записи ответа.

Путать стек и очередь. Стек поддерживает углубление и возврат, а очередь обрабатывает вершины по мере обнаружения; замена одной структуры другой меняет принцип обхода. Ошибка возникает, если ориентироваться только на название алгоритма. Проверьте правило извлечения: для глубины нужен последний добавленный элемент, для ширины — первый.

Считать, что поиск в глубину всегда находит кратчайший путь. Он может сначала уйти далеко по длинной ветви, не проверяя более короткий маршрут. Это заблуждение возникает из-за того, что алгоритм действительно находит путь, но не обязательно минимальный. Для кратчайшего пути по числу рёбер в невзвешенном графе используйте поиск в ширину.

Связь с другими темами

Для работы с обходом нужно знать, что такое вершины, рёбра и пути, а также уметь читать списки смежности: в них для каждой вершины перечислены её соседи. Обходы применяют, чтобы выяснить, достижима ли одна вершина из другой, и искать маршруты в сетях. Они служат основой для алгоритмов поиска компонент связности и кратчайших путей. Поэтому понимание очереди, стека и отметок пригодится и в других задачах на графы.

Что запомнить

  • Перед обходом выбирают исходную вершину.
  • Посещённые вершины нужно отмечать.
  • Поиск в глубину углубляется по одному пути и возвращается назад.
  • Поиск в ширину обрабатывает вершины по уровням удалённости.
  • Для поиска в глубину используют стек или рекурсию, для поиска в ширину — очередь.
  • В связном графе полный обход посещает все вершины.

Частые вопросы по теме

Зачем отмечать вершины, которые уже посетили?

Отметка не позволяет снова обрабатывать вершину и добавлять её в очередь или стек. Это особенно важно в графах с циклами: без отметок алгоритм может ходить по замкнутому маршруту бесконечно.

Почему один и тот же граф можно обходить в разном порядке?

У вершины могут быть несколько непосещённых соседей, и алгоритм вправе рассмотреть их в разном порядке. Если заранее установить правило, например проверять соседей по алфавиту, результат станет определённым.

Чем поиск в глубину отличается от поиска в ширину?

Поиск в глубину старается пройти как можно дальше по одному пути, а при необходимости возвращается к предыдущей вершине. Поиск в ширину сначала рассматривает всех ближайших соседей, а затем вершины на следующем расстоянии; для него используют очередь.

Как понять, когда при поиске в глубину нужно возвращаться назад?

Возвращаться нужно, когда у текущей вершины не осталось непосещённых соседей. Алгоритм переходит к предыдущей вершине и проверяет, есть ли у неё другие ещё не исследованные направления.

Какой алгоритм использовать, чтобы найти кратчайший путь в невзвешенном графе?

Для кратчайшего пути по числу рёбер применяют поиск в ширину. Он исследует вершины по уровням расстояния, поэтому впервые обнаруживает каждую вершину по пути с минимальным числом рёбер.

Спросить по теме параграфа

§ 53. Алгоритмы обхода связного графа

Эта же тема в других учебниках

Учебник

Оглавление →
Предмет
Информатика
Класс
11 класс
Учебник
"Информатика (базовый и углублённый уровень)", Гейн А.Г., Сенокосов А.И.