Идти вглубь до упора и возвращаться. Порядок завершения вершин даёт топологическую , три цвета — обнаружение циклов, откат состояния — перебор с возвратом.
Ключевые тезисы
- Текущее состояние обхода — это путь от старта до текущей вершины; отсюда весь перебор с возвратом.
- Три цвета вместо двух: ребро в вершину «на текущем пути» — цикл, ребро в обработанную — нет.
- Память O(глубины), а не O(V) — но на цепочке из миллиона вершин нужно заменить явным стеком.
Какую задачу решает
Половина графовых задач не про расстояния: сколько в сетке островов, есть ли в зависимостях цикл, в каком порядке собирать пакеты, как перебрать все расстановки. Здесь нужен не , а систематический обход, который ничего не пропустит и не зациклится.
идёт вглубь до упора и возвращается, когда все соседи обработаны. Побочные продукты этого порядка и есть главная ценность: порядок завершения вершин даёт топологическую , три цвета — обнаружение циклов, а откат состояния после превращает обход в полный перебор с возвратом.
Подробный разбор
«Сколько в сетке отдельных островов», «есть ли в зависимостей цикл», «в каком порядке собирать пакеты», «расставьте ферзей всеми способами» — здесь не нужен . Нужно систематически посетить всё, ничего не пропустив и не зациклившись.
эти задачи тоже решает, но хранит целый слой вершин, а главное — не даёт того, ради чего берут глубину: порядка завершения вершин, из которого выводятся топологическая сортировка, поиск циклов и компоненты.
Идти вглубь, пока есть куда, и возвращаться назад только тогда, когда все соседи текущей вершины уже обработаны.
возвратов даёт этот порядок бесплатно — его роль играет либо , либо явный стек. Поэтому текущее состояние обхода — это в точности путь от старта до текущей вершины, и на этом держится весь перебор с возвратом.
A
/ \
B C
/ \
D E
A -> B -> D
-> E
-> C
сначала ветка B целиком (D, затем E), и только потом C| Шаг | Действие | возвратов |
|---|---|---|
| 1 | входим в A | A |
| 2 | входим в B | A B |
| 3 | входим в D, соседей нет — выходим | A B |
| 4 | входим в E, соседей нет — выходим | A B |
| 5 | B обработана — выходим | A |
| 6 | входим в C, выходим; выходим из A | пусто |
Порядок выхода здесь — D, E, B, C, A. Развернув его, получаем A, C, B, E, D — корректную топологическую : каждая вершина стоит раньше тех, в кого ведут её рёбра.
WHITE, GRAY, BLACK = 0, 1, 2
color = {v: WHITE for v in graph}
order = []
def visit(v):
color[v] = GRAY # вершина на текущем пути
for u in graph[v]:
if color[u] == GRAY:
raise CycleFound # ребро назад -- цикл
if color[u] == WHITE:
visit(u)
color[v] = BLACK # поддерево пройдено
order.append(v) # порядок завершения- Время — , как и у обхода в ширину.
- Память — на возвратов, где — глубина; в худшем случае это .
- Три цвета: белая — не тронута, серая — на текущем пути, чёрная — полностью обработана.
- Топологическая сортировка — развёрнутый порядок завершения (
orderзадом наперёд).
Серая вершина — это вершина на текущем пути из корня. Ребро в серую вершину означает, что из неё можно дойти до текущей, а из текущей мы только что пришли в неё: получился цикл. Ребро в чёрную вершину цикла не означает — её поддерево уже полностью обработано и вернуться в текущий путь оттуда нельзя. Два цвета вместо трёх этой разницы не различают, и «цикл» находится там, где его нет.
Корректность топологической следует из того же: вершина становится чёрной только после всех своих потомков, значит в порядке завершения она стоит после них — а в развёрнутом порядке раньше. Если циклов нет, это и есть искомое линейное упорядочение.
| Сигнал в условии | Что применять |
|---|---|
| «Сколько компонент», «сколько островов» | из каждой непосещённой вершины |
| «Есть ли цикл в зависимостях» | обход с тремя цветами |
| «В каком порядке выполнять» при зависимостях | |
| «Переберите все расстановки, все варианты» | перебор с возвратом |
| «Можно ли разбить на две группы» | раскраска в два цвета обходом |
| «Минимальное число шагов» | не глубина, а ширина |
| Вариант | Что добавляется | Задача |
|---|---|---|
| Компоненты связности | внешний цикл по непосещённым | острова, группы пользователей |
| Поиск цикла | три цвета | зависимости пакетов, взаимные блокировки |
| порядок завершения | сборка, расписание, планы задач | |
| Двудольность | раскраска в два цвета | конфликты, распределение по сменам |
| Перебор с возвратом | откат состояния после | судоку, ферзи, перестановки |
| Мосты и точки сочленения | времена входа и минимальные достижимые | уязвимые связи в сети |
Перебор с возвратом — частный случай по неявному графу: вершины (частичные решения) не хранятся заранее, а порождаются на ходу. Отсюда и главное правило: после выхода из состояние нужно вернуть в исходное.
- Глубина рекурсии. В Python по умолчанию около тысячи кадров; на цепочке из миллиона вершин нужен явный , а не увеличение лимита.
- Два цвета вместо трёх. Ищете цикл — отличайте «на текущем пути» от «уже обработана», иначе цикл найдётся в любом ромбе.
- Родитель в неориентированном графе. Ребро назад в родителя — не цикл; его нужно исключать явно.
- Забытый откат. В переборе с возвратом состояние, изменённое перед , обязано восстанавливаться после неё.
- Обход только из одной вершины. может быть несвязным: компоненты ищутся внешним циклом по всем вершинам.
| Приём | Когда он лучше | Разница |
|---|---|---|
| Обход в ширину | нужен по числу шагов | вместо стека |
| Система непересекающихся множеств | компоненты в , который растёт по рёбрам | почти константа на операцию, но без путей |
| Алгоритм Кана | с обнаружением цикла | степеней входа, без |
| Динамика | подзадачи повторяются | обход плюс кеш вместо чистого перебора |
- Почему для поиска цикла нужны три цвета, а не два?
- Почему — это развёрнутый порядок завершения, а не порядок входа?
- Неориентированный : как отличить ребро в родителя от настоящего цикла?
- Перебор с возвратом: что произойдёт, если забыть откатить состояние?
- Цепочка из миллиона вершин: что сломается в рекурсивной реализации и чем её заменить?
Чем заменяют
Видеолекции
Тайм-кода именно на эту тему в записях нет. Но глава «Алгоритмы и структуры данных» разобрана в курсе целиком — с той оговоркой, что место в записи придётся искать самому.
Связанные темы
Алгоритмы на графах
Graph Traversal85%
Обходы графа: семейство · Алгоритмы и структуры данныхЗонтичная тема: что общего у обоих обходов, как увидеть граф в задаче, где он не назван, и по каким двум вопросам выбирается обход. Сами обходы разобраны отдельно.
Breadth-First Search85%
Поиск в ширину · Алгоритмы и структуры данныхОбход слоями: сначала всё, до чего один шаг, потом — два. Первое посещение вершины оказывается кратчайшим путём, если все переходы равноценны.
Shortest Paths85%
Кратчайшие пути · Алгоритмы и структуры данныхДейкстра для неотрицательных весов, Беллман — Форд для отрицательных, A* — когда есть оценка расстояния до цели.
Graph Basics85%
Основы графов · Графы и сетиВершины, рёбра, веса и направления. Матрица смежности и список рёбер — два способа хранить одно и то же.
Centrality85%
Центральности · Графы и сетиМеры важности вершины: по числу связей, по посредничеству, по близости и по влиянию соседей.
PageRank85%
PageRank · Графы и сетиСтационарное распределение случайного блуждания по графу с телепортацией. Классический алгоритм ранжирования, который до сих пор используется как признак.
Всё, что названо в описании, разобрано здесь же или в соседней теме — переходы под каждым определением.
Стек возвратов
Текущее состояние обхода — это путь от старта до текущей вершины.
Разбор ниже: Ключевая идеяТри цвета
Белая, серая (на текущем пути), чёрная (обработана) — так отличают цикл от ромба.
Разбор ниже: Почему это работаетПеребор с возвратом
Тот же обход по неявному графу частичных решений.
Разбор ниже: Вариации и параметрыТема встречается в тесте по направлениям — ошибки приведут обратно на эту страницу.
Глава «Алгоритмы и структуры данных» последний раз правилась . Нашли ошибку — напишите.