Построение компонент вершинной двусвязности — различия между версиями
Dimitrova (обсуждение | вклад) (→Однопроходный алгоритм) |
Dimitrova (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | == | + | ==Двупроходный алгоритм== |
− | + | Найти [[Отношение вершинной двусвязности|компоненты вершинной двусвязности]] неориентированного графа можно с помощью [[Обход_в_глубину,_цвета_вершин |обхода в глубину]]. | |
− | |||
− | |||
− | |||
'''Первый проход | '''Первый проход | ||
Используем первый проход, чтобы [[Использование обхода в глубину для поиска точек сочленения|найти точки сочленения.]] <br> | Используем первый проход, чтобы [[Использование обхода в глубину для поиска точек сочленения|найти точки сочленения.]] <br> | ||
Определим для каждой вершины две величины: <tex> enter [i] </tex> - время входа поиска в глубину в вершину <tex> i </tex>, <tex> return [i] </tex> – минимальное из времен входа вершин, достижимых из <tex> i </tex> по дереву <tex> dfs </tex> и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром. <br> | Определим для каждой вершины две величины: <tex> enter [i] </tex> - время входа поиска в глубину в вершину <tex> i </tex>, <tex> return [i] </tex> – минимальное из времен входа вершин, достижимых из <tex> i </tex> по дереву <tex> dfs </tex> и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром. <br> | ||
+ | |||
'''Псевдокод первого прохода: | '''Псевдокод первого прохода: | ||
− | + | dfs(v, parent) { | |
enter[v] = return[v] = time++; | enter[v] = return[v] = time++; | ||
used[v] = true; | used[v] = true; |
Версия 21:00, 25 ноября 2011
Содержание
Двупроходный алгоритм
Найти компоненты вершинной двусвязности неориентированного графа можно с помощью обхода в глубину.
Первый проход
Используем первый проход, чтобы найти точки сочленения.
Определим для каждой вершины две величины: - время входа поиска в глубину в вершину , – минимальное из времен входа вершин, достижимых из по дереву и не более, чем одному обратному ребру. Ребро к родителю не является обратным ребром.
Псевдокод первого прохода:
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]; иначе: если (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