1
правка
Изменения
Исправление критичного бага
==ОпределениеДвупроходный алгоритм=={{ОпределениеНайти [[Отношение вершинной двусвязности|definition = Компонентой компоненты вершинной двусвязности ]] неориентированного графа <tex>G(Vможно с помощью [[Обход_в_глубину, E)</tex> называется подмножество ребер <tex> S \subset E </tex>, такое что любые два ребра из него лежат на вершинно простом цикле_цвета_вершин |обхода в глубину]].}}
'''Второй проход:[[Точка сочленения, эквивалентные определения|Точка точка сочленения]] принадлежит как минимум двум компонентам вершинной двусвязаностидвусвязности.Вершина <tex> u v \ne root </tex> является точкой сочленения, если у нее есть сын <tex> \exists u</tex> непосредственный сын , такой что <tex> v : returnup[vu]\ge entergeqslant tin[uv] </tex>. <br> Это так же также значит, что ребро <tex> uv vu </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. Получается, что перейдя по этому ребру, мы окажемся в другой компоненте вершинной двусвязности. <br>
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br>
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
<br>
В алгоритме выполняется два прохода <tex>dfs</tex>, каждый из которых работает <tex>O(|V| + |E|)</tex>. Значит время работы алгоритма <tex>O(|V| + |E|)</tex>.
== Однопроходный алгоритм ==
Заведем [[Стек|стек]], в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека. <br>
Таким образом, каждый раз находя компоненту вершинной двусвязности мы сможем покрасить все ребра, содержащиеся в ней, в новый цвет.
=== Доказательство корректности алгоритма ===
Предположим, что граф содержит точку сочленения <tex> i' \in V </tex> , за которой следует один или несколько блоков. Вершины из этих блоков образуют подмножество <tex> V' \subset V </tex>. В таком случае: <br>
# Все вершины <tex> V' </tex> являются потомками <tex> i' </tex> в дереве обхода;
# Все вершины <tex> V' </tex> будут пройдены в течение периода серого состояния <tex> i' </tex>;
# В <tex> G </tex> не может быть обратных дуг из <tex> V' </tex> в <tex> V \setminus V' </tex>.<br>
Значит все дуги <tex> V' </tex> будут будут добавлены в стек после дуги ведущей из точки сочленения в блок. В стеке в момент обнаружения точки сочленения будут находиться только дуги блока, связанного с ней, т.к. блоки найденные до него (если таковые имеются) будет уже извлечены из стека и покрашены в свой цвет.<br>
=== Псевдокод ===
'''function''' paint(<tex>v</tex>, parent):
visited[<tex>v</tex>] = '''true'''
tin[<tex>v</tex>] = up[<tex>v</tex>] = time++
'''for''' <tex> (v, u) \in E</tex>:
'''if''' <tex>u</tex> == parent
'''continue'''
'''if''' '''not''' visited[<tex>u</tex>]
stack.push(<tex>vu</tex>)
paint(<tex>u, v</tex>)
'''if''' up[<tex>u</tex>] <tex>\geqslant</tex> tin[<tex>v</tex>]
color = maxColor++
'''while''' stack.top() != (<tex>vu</tex>)
colors[stack.top()] = color
stack.pop()
colors[<tex>vu</tex>] = color
stack.pop()
'''if''' up[<tex>u</tex>] < up[<tex>v</tex>]
up[<tex>v</tex>] = up[<tex>u</tex>]
'''else''' '''if''' tin[<tex>u</tex>] < tin[<tex>v</tex>]
stack.push(<tex>vu</tex>)
'''if''' tin[<tex>u</tex>] < up[<tex>v</tex>]
up[<tex>v</tex>] = tin[<tex>u</tex>]
'''else''' '''if''' up[<tex>v</tex>] > tin[<tex>u</tex>]
up[<tex>v</tex>] = up[<tex>u</tex>]
'''function''' solve():
'''for''' <tex> v \in V</tex>:
dfs(<tex>v</tex>)
'''for''' <tex> v \in V</tex>:
'''if''' '''not''' visited[<tex>v</tex>]:
time = 0
maxColor++
paint(<tex>v</tex>, -1)
Во время алгоритма совершается один проход <tex>dfs</tex>, который работает за <tex>O(|V| + |E|)</tex>. Внутри него совершается еще цикл, который суммарно выполняет <tex>O(|E|)</tex> операций, т.к. каждое ребро может быть добавлено в стек только один раз. Следовательно, общее время работы алгоритма <tex>O(|V| + |E|) + O(|E|) = O(|V| + |E|)</tex>
== См. также ==
* [[Использование обхода в глубину для поиска точек сочленения]]
* [[Построение компонент реберной двусвязности]]
== Источники информации ==
* В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007
* [http://rain.ifmo.ru/cat/view.php/vis/graph-general/biconnected-components-2005 Дискретная математика: Алгоритмы {{---}} Компоненты двусвязности, мосты и точки сочленения]
[[Категория: Алгоритмы и структуры данных]]
[[Категория: Обход в глубину]]