Использование обхода в глубину для поиска компонент сильной связности — различия между версиями
(→Доказательство первого утверждения) |
Dimitrova (обсуждение | вклад) (→Доказательство) |
||
Строка 9: | Строка 9: | ||
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа <tex>G</tex>.<br> | Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа <tex>G</tex>.<br> | ||
Так как компоненты сильной связности <tex>G</tex> и <tex>H</tex> графа совпадают, то первый поиск в глубину для нахождения <tex>f[u]</tex> можно выполнить на графе <tex>G</tex>, а второй - на <tex>H</tex>. | Так как компоненты сильной связности <tex>G</tex> и <tex>H</tex> графа совпадают, то первый поиск в глубину для нахождения <tex>f[u]</tex> можно выполнить на графе <tex>G</tex>, а второй - на <tex>H</tex>. | ||
− | + | ==Доказательство корректности алгоритма== | |
− | + | {{Теорема | |
− | + | |statement= | |
− | + | Вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы тогда и только тогда, когда после выполнения алгоритма оказываются в одной [[Отношение_связности,_компоненты_связности#Сильная связность|компонентe сильной связанности]]. | |
+ | |proof= | ||
− | + | ===Доказательство необходимости условия=== | |
− | Если вершины <tex>s</tex> и <tex>t</tex> были взаимно достижимы в графе <tex>G</tex>, то | + | Если вершины <tex>s</tex> и <tex>t</tex> были взаимно достижимы в графе <tex>G</tex>, то во время выполнения третьего шага алгоритма обе вершины окажутся в одном поддереве по свойству обхода в глубина. Следовательно они будут находится в одной компоненте сильной связности. |
− | + | ===Доказательство достаточности условия=== | |
− | Рассмотрим корень <tex>r</tex> дерева второго обхода в глубину, в котором оказались вершины <tex>s</tex> и <tex>t</tex>. | + | 1) Рассмотрим корень <tex>r</tex> дерева второго обхода в глубину, в котором оказались вершины <tex>s</tex> и <tex>t</tex>. Это значит, что в графе <tex>G</tex> существует путь из <tex>r</tex> в <tex>s</tex> и в <tex>t</tex>. |
+ | |||
+ | 2) Вершина <tex>r</tex> была рассмотрена вторым обходом в глубину раньше, чем <tex>s</tex> и <tex>t</tex>, значит время выхода из нее при первом обходе в глубину больше, чем время выхода из вершин <tex>s</tex> и <tex>t</tex>. Из этого мы получаем 2 случая: | ||
+ | |||
+ | а) Обе эти вершины были достижимы из <tex>r</tex> в инвертированном графе. А это означает взаимную достижимость вершин <tex>s</tex> и <tex>r</tex> и взаимную достижимость вершин <tex>r</tex> и <tex>t</tex>. А складывая пути мы получаем взаимную достижимость вершин <tex>s</tex> и <tex>t</tex>. | ||
+ | |||
+ | б) Между <tex>r</tex> и этими вершинами вообще нет пути ни в одну сторону, ни в другую при первом обходе в инверитированном графе. Но последнего быть не может, так как эти вершины были достижимы из <tex>r</tex> в графе <tex>G</tex>, а значит, вершина <tex>r</tex> достижима из них в графе <tex>H</tex>. | ||
+ | |||
+ | Значит, из случая а) и не существования случая б) получаем, что вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы в обоих графах. | ||
+ | }} | ||
==Пример реализации== | ==Пример реализации== |
Версия 09:58, 12 ноября 2011
Содержание
Постановка задачи
Дан ориентированный граф . Требуется найти в этом графе компоненты сильной связанности.
Алгоритм
Данная задачи решается с помощью поиска в глубину в 3 этапа:
- Построить граф с обратными (инвертированными) рёбрами
- Выполнить в поиск в глубину и найти - время окончания обработки вершины
- Выполнить поиск в глубину в , перебирая вершины во внешнем цикле в порядке убывания
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа
Так как компоненты сильной связности и графа совпадают, то первый поиск в глубину для нахождения можно выполнить на графе , а второй - на .
Доказательство корректности алгоритма
Теорема: |
Вершины компонентe сильной связанности. и взаимно достижимы тогда и только тогда, когда после выполнения алгоритма оказываются в одной |
Доказательство: |
Доказательство необходимости условияЕсли вершины и были взаимно достижимы в графе , то во время выполнения третьего шага алгоритма обе вершины окажутся в одном поддереве по свойству обхода в глубина. Следовательно они будут находится в одной компоненте сильной связности.Доказательство достаточности условия1) Рассмотрим корень дерева второго обхода в глубину, в котором оказались вершины и . Это значит, что в графе существует путь из в и в .2) Вершина была рассмотрена вторым обходом в глубину раньше, чем и , значит время выхода из нее при первом обходе в глубину больше, чем время выхода из вершин и . Из этого мы получаем 2 случая:а) Обе эти вершины были достижимы из в инвертированном графе. А это означает взаимную достижимость вершин и и взаимную достижимость вершин и . А складывая пути мы получаем взаимную достижимость вершин и .б) Между Значит, из случая а) и не существования случая б) получаем, что вершины и этими вершинами вообще нет пути ни в одну сторону, ни в другую при первом обходе в инверитированном графе. Но последнего быть не может, так как эти вершины были достижимы из в графе , а значит, вершина достижима из них в графе . и взаимно достижимы в обоих графах. |
Пример реализации
vector<vector<int>> g, h; //g хранит граф в виде списка смежностей, h - инвертированный vector<int> color, ord, component; //цвет вершины, список вершин в порядке окончания обработки, номер компоненты, к который относиться вершина int col; //номер текущей компоненты void dfs(int & v) //первый поиск в глубину, определяющий порядок обхода { color[v] = 1; for (unsigned i = 0; i < g[v].size(); ++i) { if (color[g[v][i]] == 0) dfs(g[v][i]); } ord.push_back(v); //добавляем вершину v в конец списка ord[] } void dfs2(int & v) //второй поиск в глубину, выявляет компоненты сильной связности в графе { component[v] = col; //помечаем вершину v как принадлежащую компоненте с номером col for (unsigned i = 0; i < h[v].size(); ++i) { if (component[h[v][i]] == 0) dfs2(h[v][i]); } } int main() { ... //считываем исходные данные, формируем массивы g и h for (int i = 1; i <= n; ++i) //формируем массив ord[] { if (color[i] == 0) dfs(i); } col = 1; for (int i = ord.size(); i > 0; --i) //ищем компоненты связности, вызывая вершины в обратном порядке { //от сохранённого в ord[], что соответствует уменьшению времени конца обработки f[] if (component[ord[i - 1]] == 0) dfs2(ord[i - 1]), col++; } }
По окончании выполнения алгоритма в
имеем номер компоненты, к которой принадлежит вершина .Литература
- Р.Седжвик. "Фундаментальные алгоритмы на С++. Алгоритмы на графах" - СПб, ДиаСофтЮП, 2002