Использование обхода в глубину для поиска компонент сильной связности — различия между версиями
(→Алгоритм) |
(→Псевдокод) |
||
| Строка 40: | Строка 40: | ||
Пусть <tex>G</tex> — исходный граф, <tex>H</tex> —инвертированный граф. В массиве <tex>ord</tex> будем хранить номера вершин в порядке окончания обработки поиском в глубину в графе <tex>G</tex>. В результате получаем массив <tex>component</tex>, который каждой вершине сопоставляет номер её компоненты. | Пусть <tex>G</tex> — исходный граф, <tex>H</tex> —инвертированный граф. В массиве <tex>ord</tex> будем хранить номера вершин в порядке окончания обработки поиском в глубину в графе <tex>G</tex>. В результате получаем массив <tex>component</tex>, который каждой вершине сопоставляет номер её компоненты. | ||
| − | ''' | + | '''function''' dfs1(v) |
| − | + | color[v] = 1 | |
| − | '''for''' (всех | + | '''for''' (всех i смежных с v) |
| − | '''if''' (вершина | + | '''if''' (вершина i не посещена) |
| − | + | dfs1(G[v][i]) | |
| − | Добавляем вершину | + | Добавляем вершину v в конец списка ord |
| − | ''' | + | '''function''' dfs2(v) |
| − | + | component[v] = col | |
| − | '''for''' (всех | + | '''for''' (всех i смежных с v) |
| − | '''if''' (если вершина | + | '''if''' (если вершина i еще не находится ни в какой компоненте) |
| − | + | dfs2(H[v][i]) | |
| − | ''' | + | '''function''' main() |
| − | считываем исходные данные, формируем массивы | + | считываем исходные данные, формируем массивы G и H |
| − | '''for''' (по всем вершинам | + | '''for''' (по всем вершинам i графа G) |
| − | '''if''' (вершина | + | '''if''' (вершина i не посещена) |
| − | + | dfs1(i) | |
| − | + | col = 1 | |
| − | '''for''' (по всем вершинам | + | '''for''' (по всем вершинам i списка ord[] в обратном порядке) |
| − | '''if''' (если вершина | + | '''if''' (если вершина i не находится ни в какой компоненте) |
| − | + | dfs2(i) | |
| − | + | col++ | |
==Литература== | ==Литература== | ||
Версия 14:14, 4 января 2016
Содержание
Алгоритм
Компоненты сильной связности в графе можно найти с помощью поиска в глубину в 3 этапа:
- Построить граф с обратными (инвертированными) рёбрами
- Выполнить в поиск в глубину и найти — время окончания обработки вершины
- Выполнить поиск в глубину в , перебирая вершины во внешнем цикле в порядке убывания
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа .
Так как компоненты сильной связности и графа совпадают, то первый поиск в глубину для нахождения можно выполнить на графе , а второй — на .
Доказательство корректности алгоритма
| Теорема: |
Вершины и взаимно достижимы после выполнения алгоритма они принадлежат одному дереву обхода в глубину. |
| Доказательство: |
|
Если вершины и были взаимно достижимы в графе , то на третьем этапе будет найден путь из одной вершины в другую, это означает, что по окончанию алгоритма обе вершины лежат в одном поддереве.
1) Вершины и лежат в одном и том же дереве поиска в глубину на третьем этапе алгоритма. Значит, что они обе достижимы из корня этого дерева. 2) Вершина была рассмотрена вторым обходом в глубину раньше, чем и , значит время выхода из нее при первом обходе в глубину больше, чем время выхода из вершин и . Из этого мы получаем 2 случая: а) Обе эти вершины были достижимы из в инвертированном графе. А это означает взаимную достижимость вершин и и взаимную достижимость вершин и . А складывая пути мы получаем взаимную достижимость вершин и . б) Хотя бы одна не достижима из в инвертированном графе, например . Значит и была не достижима из в инвертированном графе, так как время выхода - больше . Значит между этими вершинами нет пути, но последнего быть не может, потому что была достижима из по пункту 1). Значит, из случая а) и не существования случая б) получаем, что вершины и взаимно достижимы в обоих графах. |
Время работы алгоритма
- Для того, чтобы инвертировать все ребра в графе, представленном в виде списка потребуется действий. Для матричного представления графа не нужно выполнять никакие действия для его инвертирования.
- Количество ребер в инвертированном равно количеству ребер в изначальном графе, поэтому поиск в глубину будет работать за
- Поиск в глубину в исходном графе выполняется за .
В итоге получаем, что время работы алгоритма .
Псевдокод
Пусть — исходный граф, —инвертированный граф. В массиве будем хранить номера вершин в порядке окончания обработки поиском в глубину в графе . В результате получаем массив , который каждой вершине сопоставляет номер её компоненты.
function dfs1(v)
color[v] = 1
for (всех i смежных с v)
if (вершина i не посещена)
dfs1(G[v][i])
Добавляем вершину v в конец списка ord
function dfs2(v)
component[v] = col
for (всех i смежных с v)
if (если вершина i еще не находится ни в какой компоненте)
dfs2(H[v][i])
function main()
считываем исходные данные, формируем массивы G и H
for (по всем вершинам i графа G)
if (вершина i не посещена)
dfs1(i)
col = 1
for (по всем вершинам i списка ord[] в обратном порядке)
if (если вершина i не находится ни в какой компоненте)
dfs2(i)
col++
Литература
- Р.Седжвик. "Фундаментальные алгоритмы на С++. Алгоритмы на графах" - СПб, ДиаСофтЮП, 2002