Построение компонент вершинной двусвязности — различия между версиями
Dimitrova (обсуждение | вклад) |
Dimitrova (обсуждение | вклад) (→Двупроходный алгоритм) |
||
Строка 7: | Строка 7: | ||
'''Псевдокод первого прохода: | '''Псевдокод первого прохода: | ||
− | dfs(v, parent) | + | dfs(<tex>v</tex>, <tex>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> посещена) |
− | return[v] | + | <tex>return[v] \leftarrow min(return[v], enter[u])</tex> |
− | иначе | + | иначе |
− | dfs(u, v) | + | dfs(<tex>u, v</tex>) |
− | return[v] | + | <tex>return[v] \leftarrow min(return[v], return[u])</tex> |
− | + | ||
− | + | start() | |
− | + | для всех <tex>v</tex> вершин графа: | |
− | для всех v вершин графа: | + | если (<tex>v</tex> не посещена) |
− | если ( | + | <tex>time \leftarrow 0</tex> |
− | time | + | dfs(<tex>v, -1</tex>) |
− | dfs(v, -1) | ||
− | |||
'''Второй проход | '''Второй проход | ||
Строка 32: | Строка 29: | ||
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | ||
'''Псевдокод второго прохода: | '''Псевдокод второго прохода: | ||
− | + | dfs(<tex>v, c, parent</tex>) | |
− | |||
для всех вершин u смежных v: | для всех вершин u смежных v: | ||
− | если (u | + | если (<tex>u</tex> родитель) |
переходим к следующей итерации | переходим к следующей итерации | ||
− | если ( | + | если (<tex>u</tex> не посещена) |
− | если (return[u] >= enter[v]) | + | если (<tex>return[u] >= enter[v]</tex>) |
− | + | <tex>c2 \leftarrow</tex> новый цвет | |
− | col[vu] | + | <tex>col[vu] \leftarrow c2</tex> |
− | dfs(u, c2, v) | + | dfs(<tex>u, c2, v</tex>) |
− | иначе | + | иначе |
− | col[vu] | + | <tex>col[vu] \leftarrow c</tex> |
− | dfs(u, c, v) | + | dfs(<tex>u, c, v</tex>) |
иначе: | иначе: | ||
− | если (enter[u] <= enter[v]) | + | если (<tex>enter[u] <= enter[v]</tex>) |
− | col[vu] | + | <tex>col[vu] \leftarrow c</tex> |
− | + | start() | |
− | |||
− | |||
для всех v вершин графа: | для всех v вершин графа: | ||
− | если ( | + | если (<tex>v</tex> не посещена) |
− | dfs(v, -1, -1) | + | dfs(<tex>v, -1, -1</tex>) |
− | |||
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. | Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. | ||
+ | |||
+ | ==Время работы двупроходного алгоритма== | ||
+ | В алгоритме выполняется два прохода <tex>dfs</tex>, каждый из которых работает <tex>O(V + E)</tex>. Значит время работы алгоритма <tex>O(V + E)</tex>. | ||
==Однопроходный алгоритм== | ==Однопроходный алгоритм== |
Версия 06:22, 26 ноября 2011
Содержание
Двупроходный алгоритм
Найти компоненты вершинной двусвязности неориентированного графа можно с помощью обхода в глубину.
Первый проход
Используем первый проход, чтобы найти точки сочленения.
Определим для каждой вершины две величины: - время входа поиска в глубину в вершину , – минимальное из времен входа вершин, достижимых из по дереву и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром.
Псевдокод первого прохода:
dfs(, ) ++ для всех вершин смежных : если ( родитель) переходим к следующей итерации если ( посещена) иначе dfs( ) start() для всех вершин графа: если ( не посещена) dfs( )
Второй проход
Точка сочленения принадлежит как минимум двум компонентам вершинной двусвязности.
Вершина является точкой сочленения, если у нее непосредственный сын .
Это так же значит, что ребро содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину , используя поиск в глубину.
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.
Псевдокод второго прохода:
dfs() для всех вершин u смежных v: если ( родитель) переходим к следующей итерации если ( не посещена) если ( ) новый цвет dfs( ) иначе dfs( ) иначе: если ( ) start() для всех v вершин графа: если ( не посещена) dfs( )
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
Время работы двупроходного алгоритма
В алгоритме выполняется два прохода
, каждый из которых работает . Значит время работы алгоритма .Однопроходный алгоритм
Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека.
Таким образом, каждый раз находя компоненту вершинной двусвязности мы сможем покрасить все ребра, содержащиеся в ней, в новый цвет.
Доказательство корректности алгоритма
Предположим, что граф содержит точку сочленения
- Все вершины являются потомками в дереве обхода;
- Все вершины будут пройдены в течение периода серого состояния ;
- В
Значит все дуги
Псевдокод:
void dfs(v, parent) { enter[v] = return[v] = time++; used[v] = true; для всех вершин u смежных v: если (u == parent): переходим к следующей итерации если (!used[u]): stack.push(vu); dfs(u, v); если (return[u] >= enter[v]): c = newColor() пока (stack.top() <> (vu)): color[stack.top()] = c; stack.pop(); color[vu] = c; stack.pop(); если (return[u] < return[v]): return[v] = return[u]; иначе: если (enter[u] < enter[v]): stack.push(vu); если (return[v] > enter[u]): return[v] = return[u]; } void start() { used для всех вершин заполняем false для всех v вершин графа: если (!used[v]): time = 0; dfs(v, -1); }
См. также
- Использование обхода в глубину для поиска точек сочленения
- Построение компонент реберной двусвязности
- Отношение вершинной двусвязности
Литература
- В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007