Построение компонент вершинной двусвязности — различия между версиями
Kirillova (обсуждение | вклад) |
(исправлены мелкие ошибки) |
||
Строка 30: | Строка 30: | ||
} | } | ||
− | [[Точка сочленения, эквивалентные определения|Точка сочленения]] принадлежит как минимум двум компонентам вершинной | + | [[Точка сочленения, эквивалентные определения|Точка сочленения]] принадлежит как минимум двум компонентам вершинной двусвязности. |
− | Вершина <tex> u \ne root </tex> является точкой сочленения, если у нее <tex> \exists </tex> непосредственный сын <tex> v : return[v]\ge enter[u] </tex>. <br> Это так же значит, что ребро <tex> uv </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. <br> | + | Вершина <tex> u \ne root </tex> является точкой сочленения, если у нее <tex> \exists </tex> непосредственный сын <tex> v : return[v] \ge enter[u] </tex>. <br> Это так же значит, что ребро <tex> uv </tex> содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину <tex> v </tex> , используя поиск в глубину. <br> |
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.<br> | ||
'''Псевдокод второго прохода: | '''Псевдокод второго прохода: | ||
Строка 52: | Строка 52: | ||
} | } | ||
void start() { | void start() { | ||
− | |||
used для всех вершин заполняем false; | used для всех вершин заполняем false; | ||
для всех v вершин графа: | для всех v вершин графа: | ||
если (!used[v]): | если (!used[v]): | ||
− | dfs(v, | + | dfs(v, -1, -1); |
} | } | ||
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. | Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет. | ||
Строка 62: | Строка 61: | ||
==Однопроходный алгоритм== | ==Однопроходный алгоритм== | ||
Предположим, что граф содержит точку сочленения <tex> i' \in V </tex> , за которой следует один или несколько блоков, содержащих вершины <tex> V' \subset V </tex>. В таком случае: <br> | Предположим, что граф содержит точку сочленения <tex> i' \in V </tex> , за которой следует один или несколько блоков, содержащих вершины <tex> V' \subset V </tex>. В таком случае: <br> | ||
− | + | # Все вершины <tex> V' </tex> являются потомками <tex> i' </tex> в дереве обхода; | |
− | + | # Все вершины <tex> V' </tex> будут пройдены в течение периода серого состояния <tex> i' </tex>. | |
При этом в <tex> G </tex> не может быть обратных дуг из <tex> V' </tex> в <tex> V \setminus V' </tex>. Воспользуемся этим. | При этом в <tex> G </tex> не может быть обратных дуг из <tex> V' </tex> в <tex> V \setminus V' </tex>. Воспользуемся этим. | ||
Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека. | Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека. | ||
Строка 74: | Строка 73: | ||
переходим к следующей итерации | переходим к следующей итерации | ||
если (!used[u]): | если (!used[u]): | ||
− | stack | + | stack.push(vu); |
dfs(u, v); | dfs(u, v); | ||
если (return[u] >= enter[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[u] < return[v]): | ||
return[v] = return[u]; | return[v] = return[u]; | ||
Строка 94: | Строка 98: | ||
== См. также == | == См. также == | ||
− | [[Использование обхода в глубину для поиска точек сочленения]] | + | *[[Использование обхода в глубину для поиска точек сочленения]] |
− | [[Построение компонент реберной двусвязности]] | + | *[[Построение компонент реберной двусвязности]] |
==Литература== | ==Литература== | ||
* В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007 | * В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007 |
Версия 01:00, 24 декабря 2010
Содержание
Определение
Определение: |
Компонентой вершинной двусвязности графа | называется подмножество ребер , такое что любые два ребра из него лежат на вершинно простом цикле.
Построение компонент вершинной двусвязности будем осуществлять с помощью обхода в глубину.
Двупроходный алгоритм
Первый проход
Используем первый проход, чтобы найти точки сочленения.
Определим для каждой вершины две величины: - время входа поиска в глубину в вершину , – минимальное из времен входа вершин, достижимых из по дереву и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром.
Псевдокод первого прохода:
void dfs(v, parent) { enter[v] = return[v] = time++; used[v] = true; для всех вершин u смежных v: если (u == parent): переходим к следующей итерации если (used[u]): return[v] := min(return[v], enter[u]); иначе: dfs(u, v); return[v] := min(return[v], return[u]); } void start() { used для всех вершин заполняем false для всех v вершин графа: если (!used[v]): time = 0; dfs(v, -1); }
Точка сочленения принадлежит как минимум двум компонентам вершинной двусвязности.
Вершина является точкой сочленения, если у нее непосредственный сын .
Это так же значит, что ребро содержится в другой компоненте вершинной двусвязности, нежели ребро, по которому мы пришли в вершину , используя поиск в глубину.
Используем это свойство, чтобы окрасить компоненты вершинной двусвязности в различные цвета.
Псевдокод второго прохода:
void dfs(v, c, parent) { used[v] = true; для всех вершин u смежных v: если (u == parent): переходим к следующей итерации если (!used[u]): если (return[u] >= enter[v]): с2 = newColor(); col[vu] = c2; dfs(u, c2, v); иначе: col[vu] = c; dfs(u, c, v); иначе: если (enter[u] <= enter[v]): col[vu] = c; } void start() { used для всех вершин заполняем false; для всех v вершин графа: если (!used[v]): dfs(v, -1, -1); }
Ребра каждой из компонент вершинной двусвязности окажутся окрашенными в свой цвет.
Однопроходный алгоритм
Предположим, что граф содержит точку сочленения
- Все вершины являются потомками в дереве обхода;
- Все вершины будут пройдены в течение периода серого состояния .
При этом в
не может быть обратных дуг из в . Воспользуемся этим. Заведем стек, в который будем записывать все дуги в порядке их обработки. Если обнаружена точка сочленения, дуги очередного блока окажутся в этом стеке, начиная с дуги дерева обхода, которая привела в этот блок, до верхушки стека. Псевдокод: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]; иначе: если (return[v] > enter[u]): return[v] = return[u]; } void start() { used для всех вершин заполняем false для всех v вершин графа: если (!used[v]): time = 0; dfs(v, -1); }
Таким образом, каждый раз находя компоненту вершинной двусвязности мы сможем покрасить все ребра, содержащиеся в ней, в новый цвет.
См. также
- Использование обхода в глубину для поиска точек сочленения
- Построение компонент реберной двусвязности
Литература
- В.А.Кузнецов, А.М.Караваев. "Оптимизация на графах" - Петрозаводск, Издательство ПетрГУ 2007