Обход в глубину, цвета вершин — различия между версиями
(→Время работы) |
|||
Строка 69: | Строка 69: | ||
return 0; | return 0; | ||
} | } | ||
+ | |||
+ | == Дерево обхода в глубину == | ||
+ | Рассмотрим подграф предшествования обхода в глубину <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_p</tex>. | ||
== Источники == | == Источники == |
Версия 02:02, 25 октября 2011
Обход в глубину (поиск в глубину, англ. Depth-First Search, DFS) - один из основных методов обхода графа, часто используемый для проверки связности, поиска цикла и компонент сильной связности и для топологической сортировки.
Содержание
Алгоритм
Общая идея
Общая идея алгоритма состоит в следующем: для каждой не пройденной вершины необходимо найти все не пройденные смежные вершины и повторить поиск для них.
Пошаговое представление
- Выбираем любую вершину из еще не пройденных, обозначим ее как u.
- Запускаем процедуру DFS(u)
- Помечаем вершину u как пройденную
- Для каждой не пройденной смежной с u вершиной (назовем ее v) запускаем DFS(v)
- Повторяем шаги 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; }
Время работы
Оценим время работы обхода в глубину. Процедура
вызывается от каждой вершины не более одного раза, а внутри процедуры рассматриваются все такие ребра . Всего таких ребер для всех вершин в графе , следовательно, время работы алгоритма оценивается как .Цвета вершин
Зачастую, простой информации "были/не были в вершине" не хватает для конкретных целей.
Поэтому в процессе алгоритма вершинам задают некоторые цвета:
- если вершина белая, значит, мы в ней еще не были, вершина не пройдена;
- серая - вершина проходится в текущей процедуре DFS;
- черная - вершина пройдена, все итерации DFS от нее завершены.
Такие "метки" в основном используются при поиске цикла.
Реализация
Отличие реализации с цветами от предыдущей лишь в массиве 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; }
Дерево обхода в глубину
Рассмотрим подграф предшествования обхода в глубину
, где , где в свою очередь — вершина, от которой был вызван (для вершин, от которых был вызван нерекурсивно это значение соответственно равно ). Подграф предшествования поиска в глубину образует лес обхода в глубину, который состоит из нескольких деревьев обхода в глубину. Назовем ребрами дерева те ребра из , которые вошли в .