Изменения

Перейти к: навигация, поиск

Построение компонент вершинной двусвязности

716 байт добавлено, 03:37, 20 июня 2020
Исправление критичного бага
[[Категория: Обход в глубину]]
==Двупроходный алгоритм==
Найти [[Отношение вершинной двусвязности|компоненты вершинной двусвязности]] неориентированного графа можно с помощью [[Обход_в_глубину,_цвета_вершин |обхода в глубину]].
'''Первый проход:Используем первый проход, чтобы [[Использование обхода в глубину для поиска точек сочленения|найти ищем точки сочленения.с помощью обхода в глубину]] , заполняем массивы <tex>tin</tex> и <tex>up</tex>. <br>Определим для каждой вершины две величины'''Второй проход: [[Точка сочленения, эквивалентные определения|точка сочленения]] принадлежит как минимум двум компонентам вершинной двусвязности.Вершина <tex> enter v \ne root </tex> является точкой сочленения, если у нее есть сын <tex> u</tex>, такой что <tex> up[iu] \geqslant tin[v] </tex> - время входа поиска . <br> Это также значит, что ребро <tex> vu </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину . Получается, что перейдя по этому ребру, мы окажемся в другой компоненте вершинной двусвязности. <br>Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в вершину различные цвета.<br>=== Псевдокод второго прохода ===* Во время первого запуска <tex>dfs</tex> будут заполняться массивы <tex>tin</tex> и <tex> i up</tex>, поэтому при запуске функции <tex> return [i] paint</tex> – минимальное из времен входа вершинмы считаем, достижимых из что они уже посчитаны.* <tex> i \mathtt{maxColor}</tex> по дереву изначально равен <tex> dfs 0</tex> и , что эквивалентно тому, что никакое ребро не болееокрашено.* <tex>\mathtt{color}</tex> хранит в себе цвет, чем одному обратному ребрукомпоненты, из которой вызвалась функция <tex>\mathrm{paint}</tex> для текущей вершины. Ребро к родителю не является обратным ребром* <tex>\mathtt{parent}</tex> {{---}} это вершина, из которой мы попали в текущую.   '''function''' paint(<tex>v</tex>, color, parent): visited[<tex>v</tex>] = '''true''' '''for''' <tex> (v, u) \in E</tex>: '''if''' <tex>u</tex> == parent '''continue''' '''if''' '''not''' visited[<tex>u</tex>] '''if''' up[<tex>u</tex>] <tex>\geqslant</tex> tin[<tex>v</tex>] newColor = ++maxColor col[<tex>vu</tex>] = newColor paint(<tex>u</tex>, newColor, <tex>v</tex>) '''else''' col[<tex>vu</tex>] = color paint(<tex>u</tex>, color, <tex>v</tex>) '''else''' '''if''' tin[<tex>u</tex>] <brtex><</tex> tin[<tex>v</tex>] col[<tex>vu</tex>] = color
'''Псевдокод первого прохода: dfsfunction''' solve(<tex>v</tex>, <tex>parent</tex>): '''for''' <tex>enter[v] \leftarrow return[v] \leftarrow time</tex>++ для всех вершин <tex>u</tex> смежных <tex>vin V</tex>: если dfs(<tex>uv</tex> родитель) переходим к следующей итерации если (<tex>u</tex> посещена) '''for''' <tex>return[v] \leftarrow min(return[v], enter[u])in V</tex>: иначе dfs( '''if''' '''not''' visited[<tex>u, v</tex>) <tex>return[v] \leftarrow min(return[v], return[u])</tex> maxColor++ start paint() для всех <tex>v</tex> вершин графа: если (<tex>v</tex> не посещена) <tex>time \leftarrow 0</tex> dfs(<tex>v, maxColor, -1</tex>)
'''Второй проход
[[Точка сочленения, эквивалентные определения|Точка сочленения]] принадлежит как минимум двум компонентам вершинной двусвязности.
Вершина <tex> v \ne root </tex> является точкой сочленения, если у нее <tex> \exists </tex> непосредственный сын <tex> u : return[u] \ge enter[v] </tex>. <br> Это так же значит, что ребро <tex> vu </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. <br>
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br>
'''Псевдокод второго прохода:
dfs(<tex>v, c, parent</tex>)
для всех вершин u смежных v:
если (<tex>u</tex> родитель)
переходим к следующей итерации
если (<tex>u</tex> не посещена)
если (<tex>return[u] >= enter[v]</tex>)
<tex>c2 \leftarrow</tex> новый цвет
<tex>col[vu] \leftarrow c2</tex>
dfs(<tex>u, c2, v</tex>)
иначе
<tex>col[vu] \leftarrow c</tex>
dfs(<tex>u, c, v</tex>)
иначе:
если (<tex>enter[u] <= enter[v]</tex>)
<tex>col[vu] \leftarrow c</tex>
start()
для всех v вершин графа:
если (<tex>v</tex> не посещена)
dfs(<tex>v, -1, -1</tex>)
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
<br>
В алгоритме выполняется два прохода <tex>dfs</tex>, каждый из которых работает <tex>O(|V| + |E|)</tex>. Значит время работы алгоритма <tex>O(|V| + |E|)</tex>.
==Время работы двупроходного алгоритма==В алгоритме выполняется два прохода <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'Псевдокод: void dfs'' paint(<tex>v</tex>, parent) {: enter visited[<tex>v</tex>] = '''true''' tin[<tex>v</tex>] = returnup[<tex>v</tex>] = time++; used[ '''for''' <tex> (v] = true; для всех вершин , u смежных v) \in E</tex>: если ( '''if''' <tex>u </tex> == parent): переходим к следующей итерации '''continue''' если (!used '''if''' '''not''' visited[<tex>u</tex>]): stack.push(<tex>vu</tex>); dfs paint(<tex>u, v</tex>); если (return '''if''' up[<tex>u</tex>] <tex>= enter\geqslant</tex> tin[<tex>v</tex>]): c color = newColor()maxColor++ пока ( '''while''' stack.top() != (<tex> (vu</tex>)): color colors[stack.top()] = c;color stack.pop(); color colors[<tex>vu</tex>] = c;color stack.pop(); если (return '''if''' up[<tex>u</tex>] < returnup[<tex>v</tex>]): return up[<tex>v</tex>] = returnup[<tex>u</tex>]; иначе: если (enter '''else''' '''if''' tin[<tex>u</tex>] < entertin[<tex>v</tex>]): stack.push(<tex>vu</tex>); если (return '''if''' tin[<tex>u</tex>] < up[<tex>v</tex>] up[<tex>v</tex> enter] = tin[<tex>u</tex>]): return '''else''' '''if''' up[<tex>v</tex>] = return> tin[<tex>u</tex>]; } void start() { used для всех вершин заполняем false для всех v вершин графа: если (!used up[<tex>v</tex>]): time = 0; dfs(v, -1); }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 Дискретная математика: Алгоритмы {{---}} Компоненты двусвязности, мосты и точки сочленения]
 
[[Категория: Алгоритмы и структуры данных]]
[[Категория: Обход в глубину]]
1
правка

Навигация