Что делает: bruh
Где применяется: топологическая сортировка (можно ли вообще топсортить), поиск MST (Краскал, Прим)
Чего | Точная оценка | Почему |
---|---|---|
Время | O( | V |
Память | O(V) | DFS (+ стек, если надо восстановить цикл, что не влияет на асимптотику) |
Общая идея:
При обходе DFS, если вершинка смежна с серой вершиной, то существует цикл; чтобы восстановить цикл, заводим стек.
Подробнее:
В случае **ориентированного графа** произведём серию обходов. То есть из каждой вершины, в которую мы ещё ни разу не приходили, запустим поиск в глубину, который при входе в вершину будет красить её в серый цвет, а при выходе из нее — в чёрный. И, если алгоритм пытается пойти в серую вершину, то это означает, что цикл найден.
В случае **неориентированного графа**, одно ребро не должно встречаться в цикле дважды по определению. Поэтому необходимо дополнительно проверять, что текущее рассматриваемое из вершины ребро не является тем ребром, по которому мы пришли в эту вершину.
Заметим, что, если в графе есть вершины с петлями, то алгоритм будет работать корректно, так как при запуске поиска в глубину из такой вершины, найдется ребро, ведущее в нее же, а значит эта петля и будет являться циклом.
Для восстановления самого цикла достаточно при запуске поиска в глубину из очередной вершины добавлять эту вершину в **стек**. Когда поиск в глубину нашел вершину, которая лежит на цикле, будем последовательно вынимать вершины из стека, пока не встретим найденную еще раз. Все вынутые вершины будут лежать на искомом цикле
Реализация:
Просто проверка на цикл:
// псевдокод писала Я так что чекните если что не так!
string DFS(int u) {
u.color = gray // помечаем, что вершинка находится в процессе обхода
for v из G(V) do
if v.color == gray // если вершина ведёт в открытую вершину
return "There's a cycle!"
if v.color == white
DFS(v)
u.color = black // после обхода всех смежных вершин помечаем, что вершина прошла DFS
}
Восстановление цикла:
// псевдокод писала Я так что чекните если что не так!
stack<int> Vertices
vector<int> Result
void DFS(int u) {
u.color = gray // помечаем, что вершинка находится в процессе обхода
Vertices.push(u) // добавляем вершину в стек
for v из G(V) do
if v.color == gray // если вершина ведёт в открытую вершину (есть цикл)
return; // выходим из DFSа с заполненным стеком
if v.color == white
DFS(v)
u.color = black // после обхода всех смежных вершин помечаем, что вершина прошла DFS
}
int main() {
DFS(u)
int cycle_start = Vertices.front() // извлекаем верхнюю вершинку из стека
// ака начало цикла
Result.push_back(cycle.start)
for elem из Vertices do // чекаем стек пока не найдет cycle_start
if (elem != cycle_start)
Result.push_back(elem) // записываем весь цикл
else break;
}
‼ Особенности поиска и восстановления циклов:
Визуализация: этим я займусь чуть попозже