Использование обхода в глубину для поиска компонент сильной связности — различия между версиями
(→Постановка задачи) |
(→Алгоритм) |
||
Строка 3: | Строка 3: | ||
==Алгоритм== | ==Алгоритм== | ||
+ | {{Определение | ||
+ | |definition= | ||
+ | Дополнением или обратным к графу <tex>G</tex> называется такой граф <tex>H</tex>, имеющий то же множество вершин, что и <tex>G</tex>, но в котором две несовпадающие вершины смежны тогда и только тогда, когда они не смежны в <tex>G</tex>}} | ||
Данная задачи решается с помощью поиска в глубину в 3 этапа: | Данная задачи решается с помощью поиска в глубину в 3 этапа: | ||
− | #Построить | + | #Построить обратный граф |
− | #Выполнить в | + | #Выполнить в обратном графе поиск в глубину и найти <tex>f[u]</tex> - время окончания обработки вершины <tex>u</tex> |
− | #Выполнить поиск глубину в | + | #Выполнить поиск глубину в <tex>G</tex>, перебирая вершины во внешнем цикле в порядке убывания <tex>f[u]</tex> |
− | Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа | + | Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа <tex>G</tex> |
− | Так как компоненты сильной связности исходного и | + | Так как компоненты сильной связности исходного и обратного графа совпадают, то первый поиск в глубину для нахождения <tex>f[u]</tex> можно выполнить на графе <tex>G</tex>, а второй - на обратном. |
===Доказательство=== | ===Доказательство=== | ||
− | Рассмотрим пару вершин | + | Рассмотрим пару вершин <tex>s</tex> и <tex>t</tex>. |
− | Если вершины | + | Если вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы, то они обязательно будут находиться в одном дереве поиска в глубину, поскольку, когда просматривается первая из них, вторая остаётся непосещённой и достижимой из первой и будет просмотрена, прежде чем завершится рекурсивный вызов из корня. |
− | Теперь докажем, что если | + | Теперь докажем, что если <tex>s</tex> и <tex>t</tex> находятся в одном дереве поиска, то они являются сильно связанными. Пусть <tex>r</tex> - корень этого дерева. Тогда <tex>s</tex> достижима из <tex>r</tex>, из чего следует, что в обратном графе <tex>s</tex> достижима из <tex>s</tex>. Но <tex>r</tex> имеет большее время окончания обработки <tex>f[r]</tex> > <tex>f[s]</tex>, из чего следует что в обратном графе существует путь из <tex>r</tex> в <tex>s</tex>. Тогда в исходном графе существуют пути как из <tex>s</tex> в <tex>r</tex>, так и из <tex>r</tex> в <tex>s</tex>, т.е. <tex>r</tex> и <tex>s</tex> сильно связаны. Те же рассуждения доказывают, что <tex>t</tex> и <tex>r</tex> сильно связаны, из чего следует что <tex>t</tex> и <tex>s</tex> также сильно связаны. |
+ | |||
==Пример реализации== | ==Пример реализации== | ||
vector<vector<int>> g, g1; //g хранит граф в виде списка смежностей, g1 - обратный | vector<vector<int>> g, g1; //g хранит граф в виде списка смежностей, g1 - обратный |
Версия 21:30, 15 января 2011
Постановка задачи
Дан ориентированный граф G. Требуется найти в этом графе компоненты сильной связанности.
Алгоритм
Определение: |
Дополнением или обратным к графу | называется такой граф , имеющий то же множество вершин, что и , но в котором две несовпадающие вершины смежны тогда и только тогда, когда они не смежны в
Данная задачи решается с помощью поиска в глубину в 3 этапа:
- Построить обратный граф
- Выполнить в обратном графе поиск в глубину и найти - время окончания обработки вершины
- Выполнить поиск глубину в , перебирая вершины во внешнем цикле в порядке убывания
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа
Так как компоненты сильной связности исходного и обратного графа совпадают, то первый поиск в глубину для нахождения можно выполнить на графе , а второй - на обратном.Доказательство
Рассмотрим пару вершин
и . Если вершины и взаимно достижимы, то они обязательно будут находиться в одном дереве поиска в глубину, поскольку, когда просматривается первая из них, вторая остаётся непосещённой и достижимой из первой и будет просмотрена, прежде чем завершится рекурсивный вызов из корня. Теперь докажем, что если и находятся в одном дереве поиска, то они являются сильно связанными. Пусть - корень этого дерева. Тогда достижима из , из чего следует, что в обратном графе достижима из . Но имеет большее время окончания обработки > , из чего следует что в обратном графе существует путь из в . Тогда в исходном графе существуют пути как из в , так и из в , т.е. и сильно связаны. Те же рассуждения доказывают, что и сильно связаны, из чего следует что и также сильно связаны.Пример реализации
vector<vector<int>> g, g1; //g хранит граф в виде списка смежностей, g1 - обратный 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); } void dfs2(int & v) //второй поиск в глубину, выявляет компоненты сильной связности в графе { component[v] = col; for (unsigned i = 0; i < g1[v].size(); i ++ ) { if (component[g1[v][i]] == 0) dfs2(g1[v][i]); } } int main() { ... //считываем исходные данные, формируем массивы g и g1 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++; } }
По окончании выполнения алгоритма в component[i] имеем номер компоненты, к которой принадлежит вершина i