Обход в глубину, цвета вершин — различия между версиями
Glukos (обсуждение | вклад) (→Источники) |
Glukos (обсуждение | вклад) (→Дерево обхода в глубину) |
||
Строка 72: | Строка 72: | ||
== Дерево обхода в глубину == | == Дерево обхода в глубину == | ||
[[Image:tree_edges.png|thumb|270px|Типы ребер, определяемые деревом обхода]] | [[Image:tree_edges.png|thumb|270px|Типы ребер, определяемые деревом обхода]] | ||
− | Рассмотрим подграф предшествования обхода в глубину <tex>G_p = (V, E_p)</tex>, где <tex>E_p = \{(p[u], u) : u \in V,\ p[u] \neq NIL\}</tex>, где в свою очередь <tex>p[u]</tex> — вершина, от которой был вызван <tex>dfs(u)\ </tex> (для вершин, от которых <tex>dfs</tex> был вызван нерекурсивно это значение соответственно равно <tex>NIL</tex>). Подграф предшествования поиска в глубину образует ''лес обхода в глубину'', который состоит из нескольких ''деревьев обхода в глубину''. | + | Рассмотрим подграф предшествования обхода в глубину <tex>G_p = (V, E_p)</tex>, где <tex>E_p = \{(p[u], u) : u \in V,\ p[u] \neq NIL\}</tex>, где в свою очередь <tex>p[u]</tex> — вершина, от которой был вызван <tex>dfs(u)\ </tex> (для вершин, от которых <tex>dfs</tex> был вызван нерекурсивно это значение соответственно равно <tex>NIL</tex>). Подграф предшествования поиска в глубину образует ''лес обхода в глубину'', который состоит из нескольких ''деревьев обхода в глубину''. С помощью полученного леса можно классифицировать ребра графа <tex>G</tex>: |
+ | * ''Ребрами дерева'' назовем те ребра из <tex>G</tex>, которые вошли в <tex>G_p</tex>. | ||
+ | * Ребра <tex>(u, v)</tex>, соединяющие вершину <tex>u</tex> с её предком <tex>v</tex> в дереве обхода в глубину назовем ''обратными ребрами'' (для неориентированного графа предок должен быть ''не родителем'', так как иначе ребро будет являться ребром дерева). | ||
+ | * Ребра <tex>(u, v)</tex>, не являющиеся ребрами дерева и соединяющие вершину <tex>u</tex> с её потомком <tex>v</tex> в дереве обхода в глубину назовем ''прямыми ребрами'' (в неориентированном графе нет разницы между прямыми и обратными ребрами, поэтому все такие ребра считаются обратными). | ||
+ | * Все остальные ребра назовем ''перекрестными ребрами'' — такие ребра могут соединять вершины одного и того же дерева обхода в глубину, когда ни одна из вершин не является предком другой, или соединять вершины в разных деревьях. | ||
Алгоритм <tex>dfs</tex> можно модифицировать так, что он будет классифицировать встречающиеся при работе ребра. Ключевая идея состоит в том, что каждое ребро <tex>(u, v)</tex> можно классифицировать при помощи цвета вершины <tex>v</tex> при первом его исследовании, а именно: | Алгоритм <tex>dfs</tex> можно модифицировать так, что он будет классифицировать встречающиеся при работе ребра. Ключевая идея состоит в том, что каждое ребро <tex>(u, v)</tex> можно классифицировать при помощи цвета вершины <tex>v</tex> при первом его исследовании, а именно: | ||
* Белый цвет вершины <tex>v</tex> по определению <tex>dfs</tex> говорит о том, что это ''ребро дерева''. | * Белый цвет вершины <tex>v</tex> по определению <tex>dfs</tex> говорит о том, что это ''ребро дерева''. | ||
− | * Серый цвет в силу того, что серые вершины всегда образуют нисходящий путь в каком-либо из деревьев <tex>dfs</tex> и встреченная вершина <tex>v</tex> лежит на нем выше вершины <tex>u</tex>, определяет ''обратное ребро''. | + | * Серый цвет в силу того, что серые вершины всегда образуют нисходящий путь в каком-либо из деревьев <tex>dfs</tex> и встреченная вершина <tex>v</tex> лежит на нем выше вершины <tex>u</tex>, определяет ''обратное ребро''. (для неориентированного графа необходимо проверить условие <tex>v \neq p[u]</tex>) |
* Черный цвет, соответственно, указывает на ''прямое'' или ''перекрестное ребро''. | * Черный цвет, соответственно, указывает на ''прямое'' или ''перекрестное ребро''. | ||
Версия 07:49, 25 октября 2011
Обход в глубину (поиск в глубину, англ. Depth-First Search, DFS) - один из основных методов обхода графа, часто используемый для проверки связности, поиска цикла и компонент сильной связности и для топологической сортировки.
Содержание
Алгоритм
Общая идея
Общая идея алгоритма состоит в следующем: для каждой не пройденной вершины необходимо найти все не пройденные смежные вершины и повторить поиск для них.
Пошаговое представление
- Выбираем любую вершину из еще не пройденных, обозначим ее как .
- Запускаем процедуру
- Помечаем вершину u как пройденную
- Для каждой не пройденной смежной с вершиной (назовем ее ) запускаем
- Повторяем шаги 1 и 2, пока все вершины не окажутся пройденными.
Реализация
vector<bool> visited; //вектор для хранения информации о пройденных и не пройденных вершинах void dfs(int u) { visited[u] = true; //помечаем вершину как пройденную for (v таких, что (u, v) - ребро в G) //проходим по смежным с u вершинам if (!visited[v]) //проверяем, не находились ли мы ранее в выбранной вершине dfs(v); } int main() { ... //задание графа G с количеством вершин n. visited.assign(n, false); //в начале все вершины в графе не пройденные for (int i = 0; i < n; ++i) //проходим по всем вершинам графа... if (!visited[i]) //...не забыв проверить, были мы уже в очередной вершине или нет dfs(i); return 0; }
Время работы
Оценим время работы обхода в глубину. Процедура
вызывается от каждой вершины не более одного раза, а внутри процедуры рассматриваются все такие ребра . Всего таких ребер для всех вершин в графе , следовательно, время работы алгоритма оценивается как .Цвета вершин
Зачастую, простой информации "были/не были в вершине" не хватает для конкретных целей.
Поэтому в процессе алгоритма вершинам задают некоторые цвета:
- если вершина белая, значит, мы в ней еще не были, вершина не пройдена;
- серая - вершина проходится в текущей процедуре
- черная - вершина пройдена, все итерации
Такие "метки" в основном используются при поиске цикла.
Реализация
Отличие реализации с цветами от предыдущей лишь в массиве visited, который мы назовем теперь color, и дополнительной черной "метки". При этом цвета вершин будут заданы следующим образом: белый - 0, серый - 1, черный - 2.
vector<int> color; //вектор для хранения информации о цвете вершин void dfs(int u) { color[u] = 1; //раскрашиваем вершину в серый цвет for (v таких, что (u, v) - ребро в G) //проходим по смежным с u вершинам if (!color[v]) //проверяем, не находились ли мы ранее в выбранной вершине, условие не требует изменений, dfs(v); //поскольку мы считаем вершину "не пройденной" только тогда, когда она белого цвета, т.е. когда color[v] = 0 color[u] = 2; //раскрашиваем вершину в черный цвет } int main() { ... //задание графа G с количеством вершин n. color.assign(n, 0); //в начале все вершины в графе не пройденные, т.е. белые. for (int i = 0; i < n; ++i) //проходим по всем вершинам графа... if (!color[i]) //...не забыв проверить, были мы уже в очередной вершине или нет dfs(i); return 0; }
Дерево обхода в глубину
Рассмотрим подграф предшествования обхода в глубину
, где , где в свою очередь — вершина, от которой был вызван (для вершин, от которых был вызван нерекурсивно это значение соответственно равно ). Подграф предшествования поиска в глубину образует лес обхода в глубину, который состоит из нескольких деревьев обхода в глубину. С помощью полученного леса можно классифицировать ребра графа :- Ребрами дерева назовем те ребра из , которые вошли в .
- Ребра , соединяющие вершину с её предком в дереве обхода в глубину назовем обратными ребрами (для неориентированного графа предок должен быть не родителем, так как иначе ребро будет являться ребром дерева).
- Ребра , не являющиеся ребрами дерева и соединяющие вершину с её потомком в дереве обхода в глубину назовем прямыми ребрами (в неориентированном графе нет разницы между прямыми и обратными ребрами, поэтому все такие ребра считаются обратными).
- Все остальные ребра назовем перекрестными ребрами — такие ребра могут соединять вершины одного и того же дерева обхода в глубину, когда ни одна из вершин не является предком другой, или соединять вершины в разных деревьях.
Алгоритм
можно модифицировать так, что он будет классифицировать встречающиеся при работе ребра. Ключевая идея состоит в том, что каждое ребро можно классифицировать при помощи цвета вершины при первом его исследовании, а именно:- Белый цвет вершины по определению говорит о том, что это ребро дерева.
- Серый цвет в силу того, что серые вершины всегда образуют нисходящий путь в каком-либо из деревьев и встреченная вершина лежит на нем выше вершины , определяет обратное ребро. (для неориентированного графа необходимо проверить условие )
- Черный цвет, соответственно, указывает на прямое или перекрестное ребро.
Источники
- Обход в глубину на ru.wikipedia.org
- Обход в глубину на en.wikipedia.org
- Обход в глубину. Реализации.
- Томас Кормен, Чарльз Лейзерсон, Рональд Ривест, Клиффорд Штайн. Алгоритмы: построение и анализ, второе издание. Пер. с англ. — Издательский дом "Вильямс", 2007. — 1296 с. — Глава 22. Элементарные алгоритмы для работы с графами.