Построение компонент вершинной двусвязности — различия между версиями
Novik (обсуждение | вклад) м (→Источники информации) |
Novik (обсуждение | вклад) (→Двупроходный алгоритм) |
||
Строка 3: | Строка 3: | ||
'''Первый проход: | '''Первый проход: | ||
− | [[Использование обхода в глубину для поиска точек сочленения| | + | [[Использование обхода в глубину для поиска точек сочленения|ищем точки сочленения, с помощью обхода в глубину.]] <br> |
'''Второй проход: | '''Второй проход: | ||
− | [[Точка сочленения, эквивалентные определения| | + | [[Точка сочленения, эквивалентные определения|точка сочленения]] принадлежит как минимум двум компонентам вершинной двусвязности. |
Вершина <tex> v \ne root </tex> является точкой сочленения, если у нее есть сын <tex> u</tex>, такой что <tex> up[u] \geqslant tin[v] </tex>. <br> Это также значит, что ребро <tex> vu </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. Получается, что перейдя по этому ребру, мы окажемся в другой компоненте вершинной двусвязности. <br> | Вершина <tex> v \ne root </tex> является точкой сочленения, если у нее есть сын <tex> u</tex>, такой что <tex> up[u] \geqslant tin[v] </tex>. <br> Это также значит, что ребро <tex> vu </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. Получается, что перейдя по этому ребру, мы окажемся в другой компоненте вершинной двусвязности. <br> | ||
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | ||
=== Псевдокод второго прохода === | === Псевдокод второго прохода === | ||
− | * <tex>maxColor</tex> изначально равен 0, что эквивалентно тому, что ребро не окрашено. | + | * <tex>\mathtt{maxColor}</tex> изначально равен <tex>0</tex>, что эквивалентно тому, что никакое ребро не окрашено. |
− | * <tex>color</tex> хранит в себе цвет, компоненты, из которой вызвалась функция <tex>paint</tex> для текущей вершины. | + | * <tex>\mathtt{color}</tex> хранит в себе цвет, компоненты, из которой вызвалась функция <tex>paint</tex> для текущей вершины. |
− | * <tex>parent</tex> {{---}} это вершина, из которой мы попали в текущую. | + | * <tex>\mathtt{parent}</tex> {{---}} это вершина, из которой мы попали в текущую. |
'''function''' paint(<tex>v</tex>, color, parent): | '''function''' paint(<tex>v</tex>, color, parent): | ||
Строка 20: | Строка 20: | ||
'''if''' '''not''' visited[<tex>u</tex>] | '''if''' '''not''' visited[<tex>u</tex>] | ||
'''if''' up[<tex>u</tex>] <tex>\geqslant</tex> tin[<tex>v</tex>] | '''if''' up[<tex>u</tex>] <tex>\geqslant</tex> tin[<tex>v</tex>] | ||
− | newColor = | + | newColor = ++maxColor |
col[<tex>vu</tex>] = newColor | col[<tex>vu</tex>] = newColor | ||
paint(<tex>u</tex>, newColor, <tex>v</tex>) | paint(<tex>u</tex>, newColor, <tex>v</tex>) | ||
Строка 31: | Строка 31: | ||
'''function''' solve(): | '''function''' solve(): | ||
'''for''' <tex> v \in V</tex>: | '''for''' <tex> v \in V</tex>: | ||
− | + | dfs(<tex>v</tex>) | |
− | |||
− | |||
− | |||
'''for''' <tex> v \in V</tex>: | '''for''' <tex> v \in V</tex>: | ||
'''if''' '''not''' visited[<tex>v</tex>] | '''if''' '''not''' visited[<tex>v</tex>] | ||
− | paint(<tex>v</tex>, | + | maxColor++ |
+ | paint(<tex>v</tex>, maxColor, -1) | ||
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. | Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. |
Версия 23:32, 10 ноября 2015
Содержание
Двупроходный алгоритм
Найти компоненты вершинной двусвязности неориентированного графа можно с помощью обхода в глубину.
Первый проход:
ищем точки сочленения, с помощью обхода в глубину.
Второй проход:
точка сочленения принадлежит как минимум двум компонентам вершинной двусвязности.
Вершина является точкой сочленения, если у нее есть сын , такой что .
Это также значит, что ребро содержится в другой компоненте вершинной двусвязности, нежели ребро по которому мы пришли в вершину , используя поиск в глубину. Получается, что перейдя по этому ребру, мы окажемся в другой компоненте вершинной двусвязности.
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.
Псевдокод второго прохода
- изначально равен , что эквивалентно тому, что никакое ребро не окрашено.
- хранит в себе цвет, компоненты, из которой вызвалась функция для текущей вершины.
- — это вершина, из которой мы попали в текущую.
function paint(, color, parent): for : if == parent continue if not visited[ ] if up[ ] tin[ ] newColor = ++maxColor col[ ] = newColor paint( , newColor, ) else col[ ] = color paint( , color, ) else if up[ ] tin[ ] col[ ] = color
function solve(): for: dfs( ) for : if not visited[ ] maxColor++ paint( , maxColor, -1)
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
В алгоритме выполняется два прохода , каждый из которых работает . Значит время работы алгоритма .
Однопроходный алгоритм
Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека.
Таким образом, каждый раз находя компоненту вершинной двусвязности мы сможем покрасить все ребра, содержащиеся в ней, в новый цвет.
Доказательство корректности алгоритма
Предположим, что граф содержит точку сочленения
- Все вершины являются потомками в дереве обхода;
- Все вершины будут пройдены в течение периода серого состояния ;
- В
Значит все дуги
Псевдокод
function paint(, parent): tin[ ] = up[ ] = time++ for : if == parent continue if not visited[ ] stack.push( ) paint( ) if up[ ] tin[ ] color = maxColor++ while stack.top() != ( ) colors[stack.top()] = color stack.pop() colors[ ] = color stack.pop() if up[ ] < up[ ] up[ ] = up[ ] else if tin[ ] < tin[ ] stack.push( ) else if up[ ] > tin[ ] up[ ] = up[ ]
function solve(): for: if not visited[ ] dfs( ) for : visited[ ] = false for : time = 0 paint( , -1)
Во время алгоритма совершается один проход , который работает за . Внутри него совершается еще цикл, который суммарно выполняет операций, т.к. каждое ребро может быть добавлено в стек только один раз. Следовательно, общее время работы алгоритма
См. также
- Использование обхода в глубину для поиска точек сочленения
- Стек
- Построение компонент реберной двусвязности
Источники информации
- В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007
- Дискретная математика: Алгоритмы — Компоненты двусвязности, мосты и точки сочленения