Построение компонент рёберной двусвязности — различия между версиями
Shevchen (обсуждение | вклад) |
Shevchen (обсуждение | вклад) |
||
| Строка 41: | Строка 41: | ||
{{Теорема | {{Теорема | ||
|statement= | |statement= | ||
| − | Ребро <tex>uv</tex> ведет из одной компоненты реберной двусвязности в другую, если оно является частью дерева <tex>dfs</tex>, и либо <tex>u</tex> - предок <tex>v</tex> и <tex>return(v) = enter(v)</tex>, либо | + | Ребро <tex>uv</tex> ведет из одной компоненты реберной двусвязности в другую, если оно является частью дерева <tex>dfs</tex>, и либо <tex>u</tex> - предок <tex>v</tex> и <tex>return(v) = enter(v)</tex>, либо <tex>v</tex> - предок <tex>u</tex> и <tex>return(u) = enter(u)</tex>. |
|proof= | |proof= | ||
Если ребро <tex>uv</tex> - обратное, образуется цикл, содержащий <tex>uv</tex>, поэтому <tex>uv</tex> не может являться мостом. | Если ребро <tex>uv</tex> - обратное, образуется цикл, содержащий <tex>uv</tex>, поэтому <tex>uv</tex> не может являться мостом. | ||
Версия 01:40, 2 декабря 2010
Основные понятия
| Определение: |
| Две вершины и графа называются реберно двусвязными, если между этими вершинами существуют два реберно непересекающихся пути. |
| Определение: |
| Компонентами реберной двусвязности графа называют его подграфы, множества вершин которых - классы эквивалентности реберной двусвязности, а множества ребер - множества ребер из соответствующих классов эквивалентности. |
Построение компонент реберной двусвязности будет осуществляться с помощью обхода в глубину.
Двупроходный алгоритм
Первый способ найти искомые компоненты - сначала определить критерий перехода в новую компоненту реберной двусвязности, а затем покрасить вершины графа в нужные цвета.
Первый проход определяет для каждой вершины две величины: - время входа поиска в глубину в вершину, - минимальное из времен входа вершин, достижимых из по дереву и не более, чем одному обратному ребру. находится как для всех - сыновей в дереве , - соседей по обратным ребрам. Важно, что ребро к родителю дерева не является обратным ребром обхода.
Псевдокод первого прохода:
void dfs(v, родитель):
увеличиваем текущее время
enter(v) := текущее время
return(v) := enter(v)
для всех вершин u, смежных v:
если enter(u) равен нулю (вершина не посещена):
dfs(u, v)
return(v) := min(return(v), return(u))
иначе если u не родитель:
return(v) := min(return(v), enter(u))
...
обнуляем массив enter
текущее время := 0
для всех вершин v графа:
если enter(v) = 0:
dfs(v, null)
Определим критерий перехода к новой компоненте.
| Теорема: |
Ребро ведет из одной компоненты реберной двусвязности в другую, если оно является частью дерева , и либо - предок и , либо - предок и . |
| Доказательство: |
|
Если ребро - обратное, образуется цикл, содержащий , поэтому не может являться мостом. Последнее равенство означает, что из и ее потомков нельзя подняться выше по дереву обхода, в том числе, и в . Таким образом, между и существует лишь один путь - ребро , - и они принадлежат разным компонентам реберной двусвязности. |
Основываясь на этом, определим алгоритм окраски вершин графа. Путь по графу будет точно таким же, как и в первом проходе, что гарантирует постоянность дерева и определенных параметров вершин: и .
Псевдокод второго прохода:
void paint(v, цвет):
colors(v) := цвет
для всех вершин u, смежных v:
если colors(u) равен нулю (вершина не покрашена):
если return(u) = enter(u):
увеличиваем максимальный цвет
paint(u, максимальный цвет)
иначе:
paint(u, цвет)
...
обнуляем массив colors
максимальный цвет := 0
для всех вершин v графа:
если colors(v) = 0:
увеличиваем максимальный цвет
paint(v, максимальный цвет)
Вершины каждой из компонент реберной двусвязности окажутся окрашенными в свой цвет.
Однопроходный алгоритм
Можно также искать компоненты реберной двусвязности путем конкатенации циклов. Воспользуемся тем, что реберная двусвязность является отношением эквивалентности на вершинах графа; тогда, если у двух циклов существует хоть одна общая вершина, все вершины, располагающиеся на этих циклах, принадлежат одной компоненте. Более того, две вершины и лежат в одной компоненте реберной двусвязности тогда и только тогда, когда существует последовательность простых циклов , причем , , и имеет с хотя бы одну общую вершину для всех . Действительно, если зафиксировать один путь от до , а затем искать точки пересечения второго, не имеющего одинаковых ребер с первым, пути с ним, то получится последовательность циклов, точками сочленения между которыми будут как раз точки пересечения путей. И наоборот, последовательность простых циклов легко превратить в два реберно непересекающихся пути.
Совокупность компонент реберной двусвязности будем хранить как систему непересекающихся множеств вершин.
Псевдокод:
int dfs(v, родитель): (возвращает 0, если у v и ее потомков нет обратных ребер, и представителя множества, содержащего цикл с v, в обратном случае)
seen(v) = true
value = 0, result = 0
для всех вершин u, смежных v:
если не seen(u):
value = dfs(u, v)
если value > 0:
color(v) = value
result = value
иначе если u не родитель:
color(v) = color(u)
result = color(v)
return result
...
обнуляем массив seen
нумеруем вершины графа натуральными числами от 1 до мощности множества вершин графа
для всех вершин v графа:
color(v) = номер вершины (номер цвета соответствует номеру вершины-представителя в множестве)
для всех вершин v графа:
если не seen(v):
dfs(v, null)
Осталось лишь сопоставить всем вершинам отдельно взятой компоненты единственного представителя.
Псевдокод:
int relax(v): (возвращает нового представителя)
если color(v) не равен номеру v:
color(v) = relax(color(v))
return color(v)
...
для всех вершин v графа:
relax(v)
Теперь две вершины имеют одинаковый цвет тогда и только тогда, когда они принадлежат одной компоненте реберной двусвязности.