Как представлять граф и выполнять обход в глубину или ширину?
Граф состоит из вершин и рёбер, которые могут быть ориентированными, неориентированными и взвешенными. Представление выбирают по плотности и операциям. Матрица смежности быстро отвечает, есть ли ребро, список смежности экономно перечисляет соседей разреженного графа.
Матрица смежности
В таблице n × n ячейка показывает наличие или вес ребра. Память составляет O(n²) независимо от числа рёбер. Для неориентированного графа матрица симметрична, если нет дополнительной асимметричной информации.
Списки смежности
Для каждой вершины хранят список исходящих соседей. Память равна O(n + m), где m — число рёбер, а перечисление соседей занимает время, пропорциональное их числу. В неориентированном графе каждое ребро обычно записывают в двух списках.
Обход в глубину
DFS идёт по одному пути до невозможности продолжить, затем возвращается. Его реализуют рекурсией или явным стеком. Массив visited предотвращает повторные посещения и зацикливание; пометка должна происходить при обнаружении вершины, а не после полного обхода.
Обход в ширину
BFS использует очередь и рассматривает вершины слоями по расстоянию от старта. В невзвешенном графе первое обнаружение даёт минимальное число рёбер до вершины. Для восстановления маршрута сохраняют предка, через которого вершина была впервые достигнута.
Выбор и проверка
Оба обхода работают за O(n + m) на списках смежности. DFS удобен для компонент и структуры, BFS — для кратчайших невзвешенных путей. Протрассируйте граф с циклом, изолированной вершиной и несколькими компонентами; порядок обхода зависит от порядка соседей, но множество достижимых вершин — нет.
Представление выбирают по плотности графа
Список смежности занимает O(V + E) памяти и позволяет пройти исходящие рёбра вершины пропорционально их числу. Матрица занимает O(V²), зато проверяет наличие ребра за O(1). Для разреженной сети с миллионами вершин матрица часто непрактична; для небольшого плотного графа она может упростить вычисления.
from collections import deque
def bfs_distances(graph: list[list[int]], start: int) -> list[int]:
distance = [-1] * len(graph)
distance[start] = 0
queue = deque([start])
while queue:
vertex = queue.popleft()
for neighbour in graph[vertex]:
if distance[neighbour] == -1:
distance[neighbour] = distance[vertex] + 1
queue.append(neighbour)
return distanceПервое посещение в BFS даёт кратчайшее число рёбер только для невзвешенного графа. Для весов это утверждение неверно без дополнительных условий и другого алгоритма.
Практика: маршруты между аудиториями
Постройте неориентированный граф из восьми помещений и переходов. Представьте его матрицей и списками, сравните число хранимых ячеек. Найдите расстояния BFS, восстановив путь с помощью массива parent. Добавьте изолированную вершину и цикл. Затем назначьте переходам разное время и приведите контрпример, где маршрут с наименьшим числом рёбер не имеет минимального суммарного веса.
Источники
- МФТИ: Программа вступительного испытания по информатике и информационно-коммуникационным технологиям.
- МФТИ: Вступительные испытания в 2026 году.
- Ройтберг М.А. Информатика и ИКТ. Подготовка к ЕГЭ в 2017 году. Диагностические работы. — М.: МЦНМО, 2017. — 176 с.