Использование обхода в глубину для поиска точек сочленения — различия между версиями
(Отмена правки 5402 участника 192.168.0.2 (обсуждение)) |
|||
| Строка 14: | Строка 14: | ||
== Реализация == | == Реализация == | ||
| − | + | 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; | ||
| + | } | ||
== Источники == | == Источники == | ||
| − | + | Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — Ижевск: ННЦ "Регулярная и хаотическая динамика", 2001, 288 стр. | |
Версия 06:55, 1 декабря 2010
Содержание
Задача
Дан связный неориентированный граф. Требуется найти все точки сочленения в нем.
Алгоритм
Запустим обход в глубину из произвольной вершины графа . Рассмотрим :
- . Тогда, если найдётся такой потомок вершины в дереве поиска, что ни из него, ни из какого-либо его потомка нет ребра в предка вершины , то вершина будет являться точкой сочленения. В противном случае, вершина не является точкой сочленения.
- . - точка сочленения имеет хотя бы двух сыновей в дереве поиска в глубину.
Пусть - время входа поиска в глубину в вершину . Через обозначим минимум из времени захода в саму вершину , времен захода в каждую из вершин , являющуюся концом некоторого обратного ребра , а также из всех значений для каждой вершины , являющейся непосредственным сыном в дереве поиска.
Тогда, из вершины или её потомка есть обратное ребро в её предка такой сын , что .
Таким образом, если для текущей вершины непосредственный сын : , то вершина является точкой сочленения; в противном случае она точкой сочленения не является.
Реализация
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;
}
Источники
Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — Ижевск: ННЦ "Регулярная и хаотическая динамика", 2001, 288 стр.