Использование обхода в глубину для поиска компонент сильной связности — различия между версиями
Dimitrova (обсуждение | вклад) (→Псевдокод) |
(→Псевдокод) |
||
| Строка 37: | Строка 37: | ||
==Псевдокод== | ==Псевдокод== | ||
| − | + | Пусть <tex>G</tex> — исходный граф, <tex>H</tex> —инвертированный граф. В массиве <tex>ord</tex> будем хранить номера вершин в порядке окончания обработки поиском в глубину в графе <tex>G</tex>. В результате получаем массив <tex>component</tex>, который каждой вершине сопоставляет номер её компоненты. | |
| − | |||
| − | |||
| − | ''' | + | '''dfs1'''(<tex>v</tex>) |
| − | <tex>color[v] \leftarrow | + | <tex>color[v] \leftarrow</tex> 1 |
'''for''' (всех <tex>i</tex> смежных с <tex>v</tex>) | '''for''' (всех <tex>i</tex> смежных с <tex>v</tex>) | ||
'''if''' (вершина <tex>i</tex> не посещена) | '''if''' (вершина <tex>i</tex> не посещена) | ||
| − | ''' | + | '''dfs1'''(<tex>G[v][i]</tex>) |
Добавляем вершину <tex>v</tex> в конец списка <tex>ord</tex> | Добавляем вершину <tex>v</tex> в конец списка <tex>ord</tex> | ||
| Строка 52: | Строка 50: | ||
'''for''' (всех <tex>i</tex> смежных с <tex>v</tex>) | '''for''' (всех <tex>i</tex> смежных с <tex>v</tex>) | ||
'''if''' (если вершина <tex>i</tex> еще не находится ни в какой компоненте) | '''if''' (если вершина <tex>i</tex> еще не находится ни в какой компоненте) | ||
| − | '''dfs2'''(<tex>H[v][i]</tex>) | + | '''dfs2'''(<tex>H[v][i]</tex>) |
'''main'''() | '''main'''() | ||
| Строка 58: | Строка 56: | ||
'''for''' (по всем вершинам <tex>i</tex> графа <tex>G</tex>) | '''for''' (по всем вершинам <tex>i</tex> графа <tex>G</tex>) | ||
'''if''' (вершина <tex>i</tex> не посещена) | '''if''' (вершина <tex>i</tex> не посещена) | ||
| − | ''' | + | '''dfs1'''(i) |
| − | <tex>col \leftarrow | + | <tex>col \leftarrow</tex> 1 |
| − | '''for''' (по всем вершинам <tex>i</tex> списка <tex>ord[]</tex> в обратном порядке) | + | '''for''' (по всем вершинам <tex>i</tex> списка <tex>ord[]</tex> в обратном порядке) |
'''if''' (если вершина <tex>i</tex> не находится ни в какой компоненте) | '''if''' (если вершина <tex>i</tex> не находится ни в какой компоненте) | ||
| − | '''dfs2'''(<tex>i</tex>) | + | '''dfs2'''(<tex>i</tex>) |
| − | + | <tex>col</tex>++ | |
| − | |||
==Литература== | ==Литература== | ||
* Р.Седжвик. "Фундаментальные алгоритмы на С++. Алгоритмы на графах" - СПб, ДиаСофтЮП, 2002 | * Р.Седжвик. "Фундаментальные алгоритмы на С++. Алгоритмы на графах" - СПб, ДиаСофтЮП, 2002 | ||
Версия 06:31, 24 ноября 2011
Содержание
Алгоритм
Компоненты сильной связанности можно найти с помощью поиска в глубину в 3 этапа:
- Построить граф с обратными (инвертированными) рёбрами
- Выполнить в поиск в глубину и найти - время окончания обработки вершины
- Выполнить поиск в глубину в , перебирая вершины во внешнем цикле в порядке убывания
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа .
Так как компоненты сильной связности и графа совпадают, то первый поиск в глубину для нахождения можно выполнить на графе , а второй - на .
Доказательство корректности алгоритма
| Теорема: |
Вершины и взаимно достижимы после выполнения алгоритма они оказываются в одной компонентe сильной связанности. |
| Доказательство: |
|
Если вершины и были взаимно достижимы в графе , то во время выполнения третьего шага алгоритма обе вершины окажутся в одном поддереве по свойству обхода в глубина. Следовательно они будут находится в одной компоненте сильной связности.
1) Рассмотрим корень дерева второго обхода в глубину, в котором оказались вершины и . Это значит, что в графе существует путь из в и в . 2) Вершина была рассмотрена вторым обходом в глубину раньше, чем и , значит время выхода из нее при первом обходе в глубину больше, чем время выхода из вершин и . Из этого мы получаем 2 случая: а) Обе эти вершины были достижимы из в инвертированном графе. А это означает взаимную достижимость вершин и и взаимную достижимость вершин и . А складывая пути мы получаем взаимную достижимость вершин и . б) Между и этими вершинами вообще нет пути ни в одну сторону, ни в другую при первом обходе в инверитированном графе. Но последнего быть не может, так как эти вершины были достижимы из в графе , а значит, вершина достижима из них в графе . Значит, из случая а) и не существования случая б) получаем, что вершины и взаимно достижимы в обоих графах. |
Время работы алгоритма
- Для того, чтобы инвертировать все ребра в графе, представленном в виде списка потребуется действий. Для матричного представления графа ненужно выполнять никакие действия для его инвертирования.
- Количество ребер в инвертированном равно количеству ребер в изначальном графе, поэтому поиск в глубину будет работать за
- Поиск в глубину в исходном графе выполняется за .
В итоге получаем, что время работы алгоритма .
Псевдокод
Пусть — исходный граф, —инвертированный граф. В массиве будем хранить номера вершин в порядке окончания обработки поиском в глубину в графе . В результате получаем массив , который каждой вершине сопоставляет номер её компоненты.
dfs1() 1 for (всех смежных с ) if (вершина не посещена) dfs1() Добавляем вершину в конец списка dfs2() for (всех смежных с ) if (если вершина еще не находится ни в какой компоненте) dfs2() main() считываем исходные данные, формируем массивы и for (по всем вершинам графа ) if (вершина не посещена) dfs1(i) 1 for (по всем вершинам списка в обратном порядке) if (если вершина не находится ни в какой компоненте) dfs2() ++
Литература
- Р.Седжвик. "Фундаментальные алгоритмы на С++. Алгоритмы на графах" - СПб, ДиаСофтЮП, 2002