Использование обхода в глубину для поиска компонент сильной связности — различия между версиями
(→Доказательство) |
(→Доказательство первого утверждения) |
||
| Строка 16: | Строка 16: | ||
====Доказательство первого утверждения==== | ====Доказательство первого утверждения==== | ||
| − | Если вершины <tex>s</tex> и <tex>t</tex> были взаимно достижимы в графе <tex>G</tex>, то они будут взаимно достижимы и в графе <tex>H</tex>. Рассмотрим дерево обхода в глубину графа <tex>H</tex>. Поскольку вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы, то очевидно, что одна из них окажется в поддереве другой. Без потери общности скажем, что вершина <tex>t</tex> оказалась в поддереве вершины <tex> | + | Если вершины <tex>s</tex> и <tex>t</tex> были взаимно достижимы в графе <tex>G</tex>, то они будут взаимно достижимы и в графе <tex>H</tex>. Рассмотрим дерево обхода в глубину графа <tex>H</tex>. Поскольку вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы, то очевидно, что одна из них окажется в поддереве другой. Без потери общности скажем, что вершина <tex>t</tex> оказалась в поддереве вершины <tex>s</tex>. Значит, время выхода из вершины <tex>t</tex> будет меньше, чем время выхода из вершины <tex>s</tex>. Соответственно, во время третьего шага алгоритма вершина <tex>s</tex> будет рассмотрена раньше, чем вершина <tex>t</tex>, а значит, вершина <tex>s</tex> снова попадет в ее поддерево, и они окажутся в одной компоненте сильной связности. |
| + | |||
| + | ====Доказательство второго утверждения==== | ||
| + | |||
| + | Рассмотрим корень <tex>r</tex> дерева второго обхода в глубину, в котором оказались вершины <tex>s</tex> и <tex>t</tex>. В графе <tex>G</tex> существует путь из <tex>r</tex> в <tex>s</tex> и в <tex>t</tex>. Рассмотрим теперь дерево обхода графа <tex>H</tex>. То, что вершина <tex>r</tex> была рассмотрена вторым обходом в глубину раньше, чем <tex>s</tex> и <tex>t</tex>, говорит нам о том, что время выхода из нее больше, чем время выхода из вершин <tex>s</tex> и <tex>t</tex>. Это может означать, что или обе эти вершины были достижимы из <tex>r</tex>, что означает их взаимную достижимость в обоих графах, или что между <tex>r</tex> и этими вершинами вообще нет пути ни в одну сторону, ни в другую. Но последнего быть не может, так как эти вершины были достижимы из <tex>r</tex> в графе <tex>G</tex>, а значит, вершина <tex>r</tex> достижима из них в графе <tex>H</tex>. Значит, вершины <tex>s</tex> и <tex>t</tex> взаимно достижимы в обоих графах. | ||
==Пример реализации== | ==Пример реализации== | ||
Версия 00:36, 21 октября 2011
Содержание
Постановка задачи
Дан ориентированный граф . Требуется найти в этом графе компоненты сильной связанности.
Алгоритм
Данная задачи решается с помощью поиска в глубину в 3 этапа:
- Построить граф с обратными (инвертированными) рёбрами
- Выполнить в поиск в глубину и найти - время окончания обработки вершины
- Выполнить поиск в глубину в , перебирая вершины во внешнем цикле в порядке убывания
Полученные на 3-ем этапе деревья поиска в глубину будут являться компонентами сильной связности графа .
Так как компоненты сильной связности и графа совпадают, то первый поиск в глубину для нахождения можно выполнить на графе , а второй - на .
Доказательство
Докажем два утверждения:
- если вершины и взаимно достижимы, то они после работы алгоритма окажутся в одной компоненте сильной связности
- если вершины и после работы алгоритма оказались в одной компоненте сильной связности, то они взаимно достижимы
Доказательство первого утверждения
Если вершины и были взаимно достижимы в графе , то они будут взаимно достижимы и в графе . Рассмотрим дерево обхода в глубину графа . Поскольку вершины и взаимно достижимы, то очевидно, что одна из них окажется в поддереве другой. Без потери общности скажем, что вершина оказалась в поддереве вершины . Значит, время выхода из вершины будет меньше, чем время выхода из вершины . Соответственно, во время третьего шага алгоритма вершина будет рассмотрена раньше, чем вершина , а значит, вершина снова попадет в ее поддерево, и они окажутся в одной компоненте сильной связности.
Доказательство второго утверждения
Рассмотрим корень дерева второго обхода в глубину, в котором оказались вершины и . В графе существует путь из в и в . Рассмотрим теперь дерево обхода графа . То, что вершина была рассмотрена вторым обходом в глубину раньше, чем и , говорит нам о том, что время выхода из нее больше, чем время выхода из вершин и . Это может означать, что или обе эти вершины были достижимы из , что означает их взаимную достижимость в обоих графах, или что между и этими вершинами вообще нет пути ни в одну сторону, ни в другую. Но последнего быть не может, так как эти вершины были достижимы из в графе , а значит, вершина достижима из них в графе . Значит, вершины и взаимно достижимы в обоих графах.
Пример реализации
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