Алгоритм Пурдома: различия между версиями
| [непроверенная версия] | [непроверенная версия] |
Daryin (обсуждение | вклад) |
Daryin (обсуждение | вклад) |
||
| Строка 82: | Строка 82: | ||
Первый и второй этап выполняются с помощью поиска в глубину со сложностью <math>O(m)</math>. | Первый и второй этап выполняются с помощью поиска в глубину со сложностью <math>O(m)</math>. | ||
На третьем этапе основой операцией является объединение списков вершин. В случае хранения списков в отсортированном виде объединение выполняется за линейное время. Количество списков не превосходит <math>n</math>, а в каждом списке не более <math>\mu | На третьем этапе основой операцией является объединение списков вершин. В случае хранения списков в отсортированном виде объединение выполняется за линейное время. Количество списков не превосходит <math>n</math>, а в каждом списке не более <math>\mu</math> вершин, где <math>\mu</math> – количество компонент сильной связности. Общая сложность тогда составляет <math>O(\mu^2)</math>. Альтернативным форматов хранения списка вершин является битовая маска с такой же общей сложностью. | ||
Сложность четвёртого этапа составляет <math>O(n | Сложность четвёртого этапа составляет <math>O(\mu n)</math>, так как для каждой из <math>\mu</math> компонент сильной связности за линейное время вычисляется список вершин из не более чем <math>n</math> вершин. Поскольку компоненты сильной связности не пересекаются, на данном этапе уже не требуется хранить списки в отсортированном виде. | ||
Таким образом, общая сложность составляет <math>O(\mu | Таким образом, общая сложность составляет <math>O(m + \mu^2)</math>, если не требуется явное построение транзитивного замыкания, или <math>O(m + \mu n)</math> в противном случае. | ||
=== Информационный граф === | === Информационный граф === | ||
Версия от 10:34, 14 июня 2015
Свойства и структура алгоритмов
Общее описание алгоритма
Алгоритм Пурдома[1] находит транзитивное замыкание ориентированного графа за время [math]\displaystyle{ O(m + \mu n) }[/math], где [math]\displaystyle{ \mu \le m }[/math] – число компонент сильной связности этого графа.
Математическое описание
Алгоритм основан на следующих свойствах:
- Если вершины [math]\displaystyle{ v }[/math] и [math]\displaystyle{ w }[/math] принадлежат одной компоненте сильной связности графа [math]\displaystyle{ G }[/math], то его транзитивное замыкание [math]\displaystyle{ G^+ }[/math] содержит рёбра [math]\displaystyle{ (v, w) }[/math] и [math]\displaystyle{ (w, v) }[/math].
- Если вершины [math]\displaystyle{ x }[/math] и [math]\displaystyle{ y }[/math] принадлежат одной компоненте сильной связности графа [math]\displaystyle{ G }[/math], а вершины [math]\displaystyle{ z }[/math] и [math]\displaystyle{ t }[/math] – другой, то рёбра [math]\displaystyle{ (x, z) }[/math], [math]\displaystyle{ (x, t) }[/math], [math]\displaystyle{ (y, z) }[/math], [math]\displaystyle{ (y, t) }[/math] принадлежат или не принадлежат транзитивному замыканию [math]\displaystyle{ G^+ }[/math] одновременно.
Таким образом, поиск транзитивного замыкания графа [math]\displaystyle{ G }[/math] сводится к поиску транзитивного замыкания ациклического графа [math]\displaystyle{ \tilde G }[/math], полученного из [math]\displaystyle{ G }[/math] схлопыванием каждой компоненты сильной связности в одну вершину. Транзитивное замыкание ациклического графа вычисляется с использованием топологической сортировки вершин графа.
Вычислительное ядро алгоритма
Макроструктура алгоритма
Вычисления производятся в четыре этапа:
- Найти компоненты сильной связности исходного графа, заменить каждую компоненту на одну вершину и удалить образовавшиеся рёбра-петли.
- Выполнить топологическую сортировку полученного ациклического графа [math]\displaystyle{ \tilde G }[/math].
- Вычислить транзитивное замыкание графа [math]\displaystyle{ \tilde G }[/math], двигаясь от вершин с бо́льшими номерами к меньшим.
- По найденному транзитивному замыканию [math]\displaystyle{ \tilde G }[/math] восстановить транзитивное замыкание исходного графа.
Последний этап не является обязательным, если рассматривать транзитивное замыкание [math]\displaystyle{ \tilde G }[/math] как «упакованное» транзитивное замыкание [math]\displaystyle{ G }[/math].
Описание схемы реализации последовательного алгоритма
1 этап (вычисление компонент сильной связности) может быть реализован алгоритмом Тарьяна[2], находящим компоненты сильной связности в ходе поиска в глубину.
2 этап (топологическая сортировка) может быть реализован алгоритмом Кана[3] либо последовательным применением поиска в глубину[2] для нумерации вершин в предпорядке.
3 этап (транзитивное замыкание [math]\displaystyle{ \tilde G }[/math]) выполняется следующим алгоритмом:
Входные данные:
ациклический граф 'G с вершинами 'V, пронумерованными в топологическом порядке, и рёбрами E.
Выходные данные:
для каждой вершины v ∈ V – набор вершин T(v),
так что транзитивное замыкание G состоит из рёбер (v, w), v ∈ V, w ∈ T(v).
for each v ∈ V do T(v) := { v }
for v ∈ V in reverse order:
for each (v, w) ∈ E do T(v) := T(v) ∪ T(w)
4 этап (транзитивное замыкание [math]\displaystyle{ G }[/math]) либо выполняется следующим алгоритмом:
Входные данные
граф G с вершинами V;
компоненты сильной связности SCC(v) графа G;
граф [math]\displaystyle{ \tilde G }[/math] с вершинами [math]\displaystyle{ \tilde V }[/math];
транзитивное замыкание [math]\displaystyle{ \tilde T }[/math] графа [math]\displaystyle{ \tilde G }[/math].
Выходные данные:
для каждой вершины v ∈ V – набор вершин T(v),
так что транзитивное замыкание G состоит из рёбер (v, w), v ∈ V, w ∈ T(v).
for each v ∈ V do T(v) := { v }
for each v ∈ [math]\displaystyle{ \tilde V }[/math]:
for each w ∈ [math]\displaystyle{ \tilde T(v) }[/math]:
T(v) := T(v) ∪ SCC(w)
for each x ∈ SCC(v):
T(x) := T(v) /* присваивание по ссылке */
либо транзитивное замыкание может строиться по упакованным данным [math]\displaystyle{ \tilde T(v) }[/math] одной из следующих функций:
Входные данные
граф G с вершинами V;
компоненты сильной связности SCC(v) графа G;
отображение R(v) вершин графа G на вершины графа [math]\displaystyle{ \tilde G }[/math];
граф [math]\displaystyle{ \tilde G }[/math] с вершинами [math]\displaystyle{ \tilde V }[/math];
транзитивное замыкание [math]\displaystyle{ \tilde T }[/math] графа [math]\displaystyle{ \tilde G }[/math].
function transitive_closure(v):
T := { v }
for each w ∈ [math]\displaystyle{ \tilde T(R(v)) }[/math]:
T := T ∪ SCC(w)
return T
function is_in_transitive_closure(v, w):
return R(w) ∈ [math]\displaystyle{ \tilde T(R(v)) }[/math]
Последовательная сложность алгоритма
Первый и второй этап выполняются с помощью поиска в глубину со сложностью [math]\displaystyle{ O(m) }[/math].
На третьем этапе основой операцией является объединение списков вершин. В случае хранения списков в отсортированном виде объединение выполняется за линейное время. Количество списков не превосходит [math]\displaystyle{ n }[/math], а в каждом списке не более [math]\displaystyle{ \mu }[/math] вершин, где [math]\displaystyle{ \mu }[/math] – количество компонент сильной связности. Общая сложность тогда составляет [math]\displaystyle{ O(\mu^2) }[/math]. Альтернативным форматов хранения списка вершин является битовая маска с такой же общей сложностью.
Сложность четвёртого этапа составляет [math]\displaystyle{ O(\mu n) }[/math], так как для каждой из [math]\displaystyle{ \mu }[/math] компонент сильной связности за линейное время вычисляется список вершин из не более чем [math]\displaystyle{ n }[/math] вершин. Поскольку компоненты сильной связности не пересекаются, на данном этапе уже не требуется хранить списки в отсортированном виде.
Таким образом, общая сложность составляет [math]\displaystyle{ O(m + \mu^2) }[/math], если не требуется явное построение транзитивного замыкания, или [math]\displaystyle{ O(m + \mu n) }[/math] в противном случае.
Информационный граф
Описание ресурса параллелизма алгоритма
Описание входных и выходных данных
Свойства алгоритма
Программная реализация алгоритмов
Особенности реализации последовательного алгоритма
Описание локальности данных и вычислений
Возможные способы и особенности реализации параллельного алгоритма
Масштабируемость алгоритма и его реализации
Динамические характеристики и эффективность реализации алгоритма
Выводы для классов архитектур
Существующие реализации алгоритма
- Boost Graph Library (функция
transitive_closure).
Литература
- ↑ Purdom, Paul, Jr. “A Transitive Closure Algorithm.” Bit 10, no. 1 (March 1970): 76–94. doi:10.1007/BF01940892.
- ↑ 2,0 2,1 Tarjan, Robert. “Depth-First Search and Linear Graph Algorithms.” SIAM Journal on Computing 1, no. 2 (1972): 146–60.
- ↑ Kahn, A B. “Topological Sorting of Large Networks.” Communications of the ACM 5, no. 11 (November 1962): 558–62. doi:10.1145/368996.369025.