Использование обхода в глубину для поиска цикла — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(С++)
Строка 20: Строка 20:
 
===С++===
 
===С++===
  
  vector < vector<int> > graph;
+
  int graph[][];
  vector<int> color;
+
  int color[];
   
+
  dfs(int index)  
void dfs(int index)  
+
     color[index] = grey;           // красит вершину в серый цвет
{
+
     for (v : uv - ребра)
     color[index] = 1;     // красит вершину в серый цвет
+
         if ( color[v] == white )
     for (vector<int>::iterator i = graph[index].begin(); i != graph[index].end(); ++i)
+
             dfs(v);
    {
+
         if ( color[v] == grey )
         if ( color[*i] == 0 )
+
             print();             // вывод ответа   
             dfs(*i);
+
     color[index] = black;       // красит вершину в черный цвет
         if ( color[*i] == 1 )
 
             print();       // вывод ответа   
 
    }
 
     color[index] = 2;     // красит вершину в черный цвет
 
}
 
  
 
[[Категория: Алгоритмы и структуры данных]]
 
[[Категория: Алгоритмы и структуры данных]]
 
[[Категория: Обход в глубину]]
 
[[Категория: Обход в глубину]]

Версия 16:39, 22 декабря 2010

Постановка задачи

Пусть дан ориентированный граф без петель и кратных рёбер. Требуется проверить наличие цикла в этом графе.

Решим эту задачу с помощью поиска в глубину за O (M).

Алгоритм

Произведём серию поисков в глубину в графе. Т.е. из каждой вершины, в которую мы ещё ни разу не приходили, запустим поиск в глубину, который при входе в вершину будет красить её в серый цвет, а при выходе - в чёрный. И если поиск в глубину пытается пойти в серую вершину, то это означает, что мы нашли цикл.

Сам цикл можно восстановить проходом по массиву предков.

Доказательство

Пусть дан граф [math]G[/math]. Запустим [math]dfs(G)[/math]. Рассмотрим выполнение процедуры поиска в глубину от некоторой вершины [math] v [/math]. Так как все серые вершины лежат в стеке рекурсии, то для них вершина [math] v [/math] достижима по белым путям. Тогда если из рассматриваемой вершины [math] v [/math] существует ребро в серую вершину [math] u [/math], то это значит, что из вершины [math] u [/math] существует путь в [math] v [/math] и из вершины [math] v [/math] существует путь в [math] u [/math]. И так как оба эти пути не пересекаются, то существует цикл.

Реализация

Здесь приведена реализация алгоритма на С++.

С++

int graph[][];
int color[];
dfs(int index) 
    color[index] = grey;            // красит вершину в серый цвет
    for (v : uv - ребра)
        if ( color[v] == white )
            dfs(v);
        if ( color[v] == grey )
            print();             // вывод ответа   
    color[index] = black;        // красит вершину в черный цвет