Использование обхода в глубину для поиска точек сочленения — различия между версиями
(Неправильная обработка вершины-корня дерева dfs) |
Arimon (обсуждение | вклад) м (→Описание алгоритма) |
||
Строка 17: | Строка 17: | ||
Тогда из вершины <tex>u</tex> или её потомка есть обратное ребро в её предка <tex>\Leftrightarrow \exists</tex> такой сын <tex>v</tex>, что <tex>up[v] \geqslant tin[u]</tex>. | Тогда из вершины <tex>u</tex> или её потомка есть обратное ребро в её предка <tex>\Leftrightarrow \exists</tex> такой сын <tex>v</tex>, что <tex>up[v] \geqslant tin[u]</tex>. | ||
− | Таким образом, если для текущей вершины <tex> | + | Таким образом, если для текущей вершины <tex>u \ne root </tex> существует непосредственный сын <tex>v</tex>: <tex>up[v] \geqslant tin[u]</tex>, то вершина <tex>u</tex> является точкой сочленения, в противном случае она точкой сочленения не является. |
<br clear="all"> | <br clear="all"> |
Версия 00:07, 20 октября 2018
Задача: |
Дан связный неориентированный граф . Найти все точки сочленения в за время |
Содержание
Алгоритм
Описание алгоритма
Запустим обход в глубину из произвольной вершины графа; обозначим её через . Заметим следующий факт:
- Пусть мы находимся в обходе в глубину, просматривая сейчас все рёбра из вершины . Тогда, если текущее ребро ( , ) таково, что из вершины и из любого её потомка в дереве обхода в глубину нет обратного ребра в вершину или какого-либо её предка, то это ребро является мостом. В противном случае оно мостом не является. (В самом деле, мы этим условием проверяем, нет ли другого пути из в , кроме как спуск по ребру ( , ) дерева обхода в глубину.)
Теперь осталось научиться проверять этот факт для каждой вершины эффективно. Для этого воспользуемся "временами входа в вершину", вычисляемыми алгоритмом поиска в глубину.
Пусть
— время входа поиска в глубину в вершину . Через обозначим минимум из времени захода в саму вершину , времен захода в каждую из вершин , являющуюся концом некоторого обратного ребра , а также из всех значений для каждой вершины , являющейся непосредственным сыном в дереве поиска.Тогда из вершины
или её потомка есть обратное ребро в её предка такой сын , что .Таким образом, если для текущей вершины
существует непосредственный сын : , то вершина является точкой сочленения, в противном случае она точкой сочленения не является.
Псевдокод
function findCutPoints(G[n]: Graph): // функция принимает граф G с количеством вершин n и выполняет поиск точек сочленения во всем графе visited = array[n, false] function dfs(v: int, p: int): time = time + 1 up[v] = tin[v] = time visited[v] = true count = 0 for u: (v, u) in G if u == p continue if visited[u] up[v] = min(up[v], tin[u]) else dfs(u, v) count = count + 1 up[v] = min(up[v], up[u]) if p != -1 and up[u] >= tin[v] v — cutpoint if p == -1 and count >= 2 v — cutpoint for i = 1 to n if not visited[i] dfs(i, -1)
Доказательство корректности
Теорема: |
Пусть обхода в глубину, — корень .
— дерево
|
Доказательство: |
|
Асимптотика
Оценим время работы алгоритма. Процедура ребра . Всего таких ребер для всех вершин в графе , следовательно, время работы алгоритма оценивается как . Такое же, как у обхода в глубину.
вызывается от каждой вершины не более одного раза, а внутри процедуры рассматриваются все такиеСм. также
Источники информации
- Асанов М., Баранский В., Расин В. — Дискретная математика: Графы, матроиды, алгоритмы — Лань, 2010. — 368 с. — ISBN 978-5-8114-1068-2
- MAXimal :: algo :: Поиск точек сочленения