Использование обхода в глубину для поиска точек сочленения — различия между версиями
(→Алгоритм) |
|||
Строка 5: | Строка 5: | ||
{{Теорема | {{Теорема | ||
|statement= | |statement= | ||
− | Пусть <tex>T</tex> | + | Пусть <tex>T</tex> — дерево [[Обход в глубину, цвета вершин|обхода в глубину]], <tex>root</tex> — корень <tex>T</tex>. Вершина <tex>u \ne root</tex> — точка сочленения <tex>\Leftrightarrow \exists v \in T</tex> — сын <tex>u</tex> : из <tex>v</tex> или любого потомка вершины <tex>v</tex> нет обратного ребра в предка вершины <tex>u</tex>. <tex>root</tex> — точка сочленения <tex>\Leftrightarrow root</tex> имеет хотя бы двух сыновей в дереве поиска в глубину. |
|proof= | |proof= | ||
<tex>\Leftarrow</tex> | <tex>\Leftarrow</tex> | ||
− | #Удалим <tex>u</tex> из <tex>G</tex>. Докажем, что не существует пути из <tex>v</tex> в любого предка вершины <tex>u</tex>. Пусть это не так. Тогда <tex>\exists x \in T</tex> | + | #Удалим <tex>u</tex> из <tex>G</tex>. Докажем, что не существует пути из <tex>v</tex> в любого предка вершины <tex>u</tex>. Пусть это не так. Тогда <tex>\exists x \in T</tex> — предок <tex>u</tex> : <tex>\exists</tex> путь из <tex>v</tex> в <tex>x</tex> в <tex>G \backslash u</tex>. Пусть <tex>w</tex> — предпоследняя вершина на этом пути, <tex>w</tex> — потомок <tex>v</tex>. <tex>(w, x)</tex> — не ребро дерева <tex>T</tex>(в силу единственности пути в дереве) <tex>\Rightarrow (w, x)</tex> — обратное ребро, что противоречит условию. |
− | #Пусть у <tex>root</tex> хотя бы два сына. Тогда при удалении <tex>root</tex> не существует пути между его поддеревьями, так как не существует перекрестных ребер <tex>\Rightarrow root</tex> | + | #Пусть у <tex>root</tex> хотя бы два сына. Тогда при удалении <tex>root</tex> не существует пути между его поддеревьями, так как не существует перекрестных ребер <tex>\Rightarrow root</tex> — точка сочленения. |
<tex>\Rightarrow</tex> | <tex>\Rightarrow</tex> | ||
− | #Докажем что из отрицания второго утверждения следует отрицание первого. Обозначим через <tex>G'</tex> граф, состоящий из вершин, не являющихся потомками <tex>u</tex>. Удалим вершину <tex>u</tex>. Очевидно, что граф <tex>G'</tex> и все поддеревья вершины <tex>u</tex> останутся связными, кроме того из каждого поддерева есть ребро в <tex>G' \Rightarrow G \backslash u</tex> | + | #Докажем что из отрицания второго утверждения следует отрицание первого. Обозначим через <tex>G'</tex> граф, состоящий из вершин, не являющихся потомками <tex>u</tex>. Удалим вершину <tex>u</tex>. Очевидно, что граф <tex>G'</tex> и все поддеревья вершины <tex>u</tex> останутся связными, кроме того из каждого поддерева есть ребро в <tex>G' \Rightarrow G \backslash u</tex> — связный <tex>\Rightarrow u</tex> — не точка сочленения. |
− | #Пусть <tex>root</tex> | + | #Пусть <tex>root</tex> — точка сочленения и у него есть только один сын. Тогда при удалении <tex>root</tex> остается дерево с корнем в его сыне, содержащее все остальные вершины графа, то есть оставшийся граф связен — противоречие с тем, что <tex>root</tex> — точка сочленения. |
}} | }} | ||
− | Пусть <tex>tin[u]</tex> | + | Пусть <tex>tin[u]</tex> — время входа поиска в глубину в вершину <tex>u</tex>. Через <tex>up[u]</tex> обозначим минимум из времени захода в саму вершину <tex>tin[u]</tex>, времен захода в каждую из вершин <tex>p</tex>, являющуюся концом некоторого обратного ребра <tex>(u,p)</tex>, а также из всех значений <tex>up[v]</tex> для каждой вершины <tex>v</tex>, являющейся непосредственным сыном <tex>u</tex> в дереве поиска. |
Тогда из вершины <tex>u</tex> или её потомка есть обратное ребро в её предка <tex>\Leftrightarrow \exists</tex> такой сын <tex>v</tex>, что <tex>up[v] < tin[u]</tex>. | Тогда из вершины <tex>u</tex> или её потомка есть обратное ребро в её предка <tex>\Leftrightarrow \exists</tex> такой сын <tex>v</tex>, что <tex>up[v] < tin[u]</tex>. | ||
Строка 31: | Строка 31: | ||
if (<tex>v</tex> родитель <tex>u</tex>) | if (<tex>v</tex> родитель <tex>u</tex>) | ||
Переходим к следующей итерации цикла | Переходим к следующей итерации цикла | ||
− | if (<tex>v</tex> посещено) //v | + | if (<tex>v</tex> посещено) //<tex>v</tex> — предок вершины <tex>u</tex>, <tex>uv</tex> — обратное ребро |
<tex>up[u] \leftarrow min(up[u], tin[v])</tex> | <tex>up[u] \leftarrow min(up[u], tin[v])</tex> | ||
− | else | + | else //<tex>v</tex> — ребенок вершины <tex>u</tex> |
<tex>count</tex>++ | <tex>count</tex>++ | ||
dfs(<tex>v, u</tex>) | dfs(<tex>v, u</tex>) | ||
Строка 49: | Строка 49: | ||
dfs(<tex>root</tex>, -1); | dfs(<tex>root</tex>, -1); | ||
<br> | <br> | ||
− | Время работы алгоритма совпадает с временем работы <tex> dfs | + | Время работы алгоритма совпадает с [[Обход в глубину, цвета вершин#Время работы|временем работы]] <tex> dfs </tex>. |
= Источники = | = Источники = | ||
Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — Ижевск: ННЦ "Регулярная и хаотическая динамика", 2001, 288 стр. | Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — Ижевск: ННЦ "Регулярная и хаотическая динамика", 2001, 288 стр. |
Версия 10:54, 11 декабря 2011
Алгоритм
Дан связный неориентированный граф. Требуется найти все точки сочленения в нем.
Теорема: |
Пусть обхода в глубину, — корень . Вершина — точка сочленения — сын : из или любого потомка вершины нет обратного ребра в предка вершины . — точка сочленения имеет хотя бы двух сыновей в дереве поиска в глубину. — дерево |
Доказательство: |
|
Пусть
— время входа поиска в глубину в вершину . Через обозначим минимум из времени захода в саму вершину , времен захода в каждую из вершин , являющуюся концом некоторого обратного ребра , а также из всех значений для каждой вершины , являющейся непосредственным сыном в дереве поиска.Тогда из вершины
или её потомка есть обратное ребро в её предка такой сын , что .Таким образом, если для текущей вершины
существует непосредственный сын : , то вершина является точкой сочленения, в противном случае она точкой сочленения не является.Реализация
dfs(, ) Помечаем вершину , как посещенную ++ 0 for ( : из ) if ( родитель ) Переходим к следующей итерации цикла if ( посещено) // — предок вершины , — обратное ребро else // — ребенок вершины ++ dfs( ) if ( >= ) if ( корень) main() ... for ( из ) if ( не посещен) dfs( , -1);
Время работы алгоритма совпадает с временем работы .
Источники
Асанов М., Баранский В., Расин В. - Дискретная математика: Графы, матроиды, алгоритмы — Ижевск: ННЦ "Регулярная и хаотическая динамика", 2001, 288 стр.