Построение компонент рёберной двусвязности — различия между версиями
Shevchen (обсуждение | вклад) |
Shevchen (обсуждение | вклад) |
||
Строка 21: | Строка 21: | ||
Псевдокод первого прохода: | Псевдокод первого прохода: | ||
− | ''' | + | '''void dfs(v, родитель): |
− | |||
− | |||
увеличиваем текущее время | увеличиваем текущее время | ||
enter(v) := текущее время | enter(v) := текущее время | ||
Строка 34: | Строка 32: | ||
return(v) := min(return(v), enter(u)) | return(v) := min(return(v), enter(u)) | ||
... | ... | ||
+ | обнуляем массив enter | ||
+ | текущее время := 0 | ||
для всех вершин v графа: | для всех вершин v графа: | ||
если enter(v) = 0: | если enter(v) = 0: | ||
Строка 51: | Строка 51: | ||
Псевдокод второго прохода: | Псевдокод второго прохода: | ||
− | ''' | + | '''void paint(v, цвет): |
− | |||
− | |||
colors(v) := цвет | colors(v) := цвет | ||
для всех вершин u, смежных v: | для всех вершин u, смежных v: | ||
Строка 63: | Строка 61: | ||
paint(u, цвет) | paint(u, цвет) | ||
... | ... | ||
+ | обнуляем массив colors | ||
+ | максимальный цвет := 0 | ||
для всех вершин v графа: | для всех вершин v графа: | ||
если colors(v) = 0: | если colors(v) = 0: | ||
Строка 69: | Строка 69: | ||
Вершины каждой из компонент реберной двусвязности окажутся окрашенными в свой цвет. | Вершины каждой из компонент реберной двусвязности окажутся окрашенными в свой цвет. | ||
+ | |||
+ | == Однопроходный алгоритм == | ||
+ | |||
+ | Можно также искать компоненты реберной двусвязности путем конкатенации циклов. Воспользуемся тем, что реберная двусвязность является отношением эквивалентности на вершинах графа; тогда, если у двух циклов существует хоть одна общая вершина, все вершины, располагающиеся на этих циклах, принадлежат одной компоненте. Более того, две вершины <tex>u</tex> и <tex>v</tex> лежат в одной компоненте реберной двусвязности тогда и только тогда, когда существует последовательность простых циклов <tex>c_1 c_2 ... c_n</tex>, причем <tex>u \in c_1</tex>, <tex>v \in c_n</tex>, и <tex>c_i</tex> имеет с <tex>c_{i + 1}</tex> хотя бы одну общую вершину для всех <tex>i \in {1 ... n - 1}</tex>. Действительно, если зафиксировать один путь от <tex>u</tex> до <tex>v</tex>, а затем искать точки пересечения второго, не имеющего одинаковых ребер с первым, пути с ним, то получится последовательность циклов, точками сочленения между которыми будут как раз точки пересечения путей. И наоборот, последовательность простых циклов легко превратить в два реберно непересекающихся пути. | ||
+ | |||
+ | Совокупность компонент реберной двусвязности будем хранить как систему непересекающихся множеств вершин. | ||
+ | |||
+ | Псевдокод: | ||
+ | |||
+ | '''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) | ||
+ | |||
+ | Теперь две вершины имеют одинаковый цвет тогда и только тогда, когда они принадлежат одной компоненте реберной двусвязности. | ||
== См. также == | == См. также == | ||
[[Отношение реберной двусвязности]] | [[Отношение реберной двусвязности]] |
Версия 05:04, 26 ноября 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)
Теперь две вершины имеют одинаковый цвет тогда и только тогда, когда они принадлежат одной компоненте реберной двусвязности.