Использование обхода в глубину для поиска точек сочленения
Версия от 05:52, 1 декабря 2010; 192.168.0.2 (обсуждение) (Новая страница: «== Задача == Дан связный [[Основные определения…»)
Содержание
Задача
Дан связный неориентированный граф. Требуется найти все точки сочленения в нем.
Алгоритм
Запустим обход в глубину из произвольной вершины графа . Рассмотрим :
- . Тогда, если найдётся такой потомок вершины в дереве поиска, что ни из него, ни из какого-либо его потомка нет ребра в предка вершины , то вершина будет являться точкой сочленения. В противном случае, вершина не является точкой сочленения.
- . - точка сочленения имеет хотя бы двух сыновей в дереве поиска в глубину.
Пусть
- время входа поиска в глубину в вершину . Через обозначим минимум из времени захода в саму вершину , времен захода в каждую из вершин , являющуюся концом некоторого обратного ребра , а также из всех значений для каждой вершины , являющейся непосредственным сыном в дереве поиска.Тогда, из вершины
или её потомка есть обратное ребро в её предка такой сын , что .Таким образом, если для текущей вершины
непосредственный сын : , то вершина является точкой сочленения; в противном случае она точкой сочленения не является.Реализация
bool used[]; int tin[]; int up[]; bool answer[]; //для каждой вершины содержится булево значение - является она точкой сочленения или нет. изначально все значения false int time; void dfs(int u, int prev) { used[u] = true; tin[u] = up[u] = time++; //задание времени входа tin и начального значения up для вершины u int count = 0; //счетчик количества детей вершины u в дереве обхода for (v : uv из E) { if (v == prev) continue; if (used[v]) //v - предок вершины u, uv - обратное ребро up[u] = min(up[u], tin[v]); else //v - ребенок вершины u { ++count; dfs(v, u); up[u] = min(up[u], up[v]); if (up[v] >= tin[u]) answer[u] = true; //не существует обратного ребра из вершины v или ее потомка в предка вершины u. вершина u - точка сочленения } } if (p == -1) //является ли u корнем дерева обхода answer[u] = (count > 1); //проверка количества детей у корня дерева } int main() { ... //инициализация графа, выбор корня дерева обхода root time = 0; dfs(root, -1); return 0; }
Для поиска точек сочленения в несвязном графе, необходимо модифицировать функцию main следующим образом:
int main() { ... for (root из V) if (!used[root]) { time = 0; dfs(root, -1); } return 0; }