Построение компонент вершинной двусвязности — различия между версиями
Dimitrova (обсуждение | вклад) |
Dimitrova (обсуждение | вклад) (→Однопроходный алгоритм) |
||
| Строка 64: | Строка 64: | ||
Значит все дуги <tex> V' </tex> будут будут добавлены в стеке после дуги ведущей из точки сочленения в блок. В стеке в момент обнаружения точки сочленения будут находиться только дуги блока, связанного с ней, т.к. блоки найденный до него (если таковые имеется) будет извлечен уже из стека и помечены в свой цвет.<br> | Значит все дуги <tex> V' </tex> будут будут добавлены в стеке после дуги ведущей из точки сочленения в блок. В стеке в момент обнаружения точки сочленения будут находиться только дуги блока, связанного с ней, т.к. блоки найденный до него (если таковые имеется) будет извлечен уже из стека и помечены в свой цвет.<br> | ||
'''Псевдокод: | '''Псевдокод: | ||
| − | + | dfs(<tex>v, parent</tex>) | |
| − | enter[v] | + | <tex>enter[v] \leftarrow return[v] \leftarrow time</tex>++ |
| − | + | для всех вершин <tex>u</tex> смежных <tex>v</tex>: | |
| − | для всех вершин u смежных v: | + | если (<tex>u</tex> родитель) |
| − | если (u | ||
переходим к следующей итерации | переходим к следующей итерации | ||
| − | если ( | + | если (<tex>u</tex> не посещена) |
| − | + | добавить в стек ребро<tex>vu</tex> | |
| − | dfs(u, v) | + | dfs(<tex>u, v</tex>) |
| − | если (return[u] >= enter[v]) | + | если (<tex>return[u] >= enter[v]</tex>) |
| − | c | + | <tex>c \leftarrow </tex> новый цвет |
| − | пока ( | + | пока (ребро <tex>vu</tex> не равно вершине стека) |
| − | color[ | + | <tex>color</tex>[вершина стека] <tex> \leftarrow c</tex> |
| − | + | извлечь вершину стека | |
| − | color[vu] | + | <tex>color[vu] \leftarrow c</tex> |
| − | + | извлечь вершину стека | |
| − | если (return[u] < return[v]) | + | если (<tex>return[u] < return[v]</tex>) |
| − | return[v] | + | <tex>return[v] \leftarrow return[u]</tex> |
| − | иначе | + | иначе |
| − | если (enter[u] < enter[v]) | + | если (<tex>enter[u] < enter[v]</tex>) |
| − | + | добавить в стек ребро <tex>vu</tex> | |
| − | если (return[v] > enter[u]) | + | если (<tex>return[v] > enter[u]</tex>) |
| − | return[v] | + | <tex>return[v] \leftarrow return[u]</tex> |
| − | + | start() | |
| − | + | для всех <tex>v</tex> вершин графа: | |
| − | + | если (<tex>v</tex> не посещена) | |
| − | для всех v вершин графа: | + | <tex>time \leftarrow 0</tex> |
| − | если ( | + | dfs(<tex>v</tex>, -1) |
| − | time | + | |
| − | dfs(v, -1) | + | ==Время работы однопроходного алгоритма== |
| − | + | Во время алгоритма совершается один проход <tex>dfs</tex>, который работает за <tex>O(V + E)</tex>. Внутри него совершается еще цикл, уоторый суммарно выполняет <tex>O(E)</tex> операций, т.к. каждое ребро может быть добавлено в стек только один раз. Следовательно Общее время работы алгоритма <tex>O(V + E) + O(E) = O(V + E)</tex> | |
==Литература== | ==Литература== | ||
* В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007 | * В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007 | ||
Версия 06:39, 26 ноября 2011
Содержание
Двупроходный алгоритм
Найти компоненты вершинной двусвязности неориентированного графа можно с помощью обхода в глубину.
Первый проход
Используем первый проход, чтобы найти точки сочленения.
Определим для каждой вершины две величины: - время входа поиска в глубину в вершину , – минимальное из времен входа вершин, достижимых из по дереву и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром.
Псевдокод первого прохода:
dfs(, ) ++ для всех вершин смежных : если ( родитель) переходим к следующей итерации если ( посещена) иначе dfs() start() для всех вершин графа: если ( не посещена) dfs()
Второй проход
Точка сочленения принадлежит как минимум двум компонентам вершинной двусвязности.
Вершина является точкой сочленения, если у нее непосредственный сын .
Это так же значит, что ребро содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину , используя поиск в глубину.
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.
Псевдокод второго прохода:
dfs() для всех вершин u смежных v: если ( родитель) переходим к следующей итерации если ( не посещена) если () новый цвет dfs() иначе dfs() иначе: если () start() для всех v вершин графа: если ( не посещена) dfs()
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
Время работы двупроходного алгоритма
В алгоритме выполняется два прохода , каждый из которых работает . Значит время работы алгоритма .
Однопроходный алгоритм
Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека.
Таким образом, каждый раз находя компоненту вершинной двусвязности мы сможем покрасить все ребра, содержащиеся в ней, в новый цвет.
Доказательство корректности алгоритма
Предположим, что граф содержит точку сочленения , за которой следует один или несколько блоков. Вершины из этих блоков образуют подмножество . В таком случае:
- Все вершины являются потомками в дереве обхода;
- Все вершины будут пройдены в течение периода серого состояния ;
- В не может быть обратных дуг из в .
Значит все дуги будут будут добавлены в стеке после дуги ведущей из точки сочленения в блок. В стеке в момент обнаружения точки сочленения будут находиться только дуги блока, связанного с ней, т.к. блоки найденный до него (если таковые имеется) будет извлечен уже из стека и помечены в свой цвет.
Псевдокод:
dfs() ++ для всех вершин смежных : если ( родитель) переходим к следующей итерации если ( не посещена) добавить в стек ребро dfs() если () новый цвет пока (ребро не равно вершине стека) [вершина стека] извлечь вершину стека извлечь вершину стека если () иначе если () добавить в стек ребро если () start() для всех вершин графа: если ( не посещена) dfs(, -1)
Время работы однопроходного алгоритма
Во время алгоритма совершается один проход , который работает за . Внутри него совершается еще цикл, уоторый суммарно выполняет операций, т.к. каждое ребро может быть добавлено в стек только один раз. Следовательно Общее время работы алгоритма
Литература
- В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007