2010-03-26 5 views
26

Как определить, является ли направленный граф циклическим? Я думал, используя первый поиск по ширине, но я не уверен. Есть идеи?Как определить, является ли направленный граф циклическим?

+0

возможно дубликат [Как я могу проверить, если ориентированный граф ациклический?] (Http://stackoverflow.com/questions/583876/how- do-i-check-if-a-direct-graph-is-acyclic) –

+0

Я только что опубликовал общее решение FP для Scala в связанном потоке StackOverflow: http://stackoverflow.com/a/36144158/501113 – chaotic3quilibrium

ответ

13

Обычно вместо этого используется поиск по глубине. Я не знаю, легко ли BFS.

В DFS остовное дерево построено в порядке посещения. Если посетитель предка узла в дереве посещается (т. Е. Создается обратный край), мы обнаруживаем цикл.

См. http://www.cs.nyu.edu/courses/summer04/G22.1170-001/6a-Graphs-More.pdf для более подробного объяснения.

+1

BFS или DFS имеют одинаковую сложность (время выполнения) и применимость (тот же результат) по этой проблеме. Единственное различие заключается в порядке посещения узлов. – darlinton

+0

Последний оператор на странице, указанный в ссылке, является топологическим утверждением, основанным на числе ребер и вершин: «Максимальное количество возможных ребер в графе G, если оно не имеет цикла, равно | V | - 1. " Это верно для * ненаправленных * графиков, но не для * направленных * графиков, как указано в исходном вопросе. Для ориентированных графов диаграмма «наследование алмаза» дает контрпример (4 узла и 4 ребра образуют «цикл», но не «цикл», который можно пройти по стрелкам). – Peter

+3

В случае, если последний комментарий не был ясен - я говорю, что принятого ответа достаточно для неориентированных графов, но * неверно * для ориентированных графов (как указано в вопросе). – Peter

-1

Другим простым решением будет подход с меткой и разверткой. В принципе, для каждого узла в дереве вы указываете его как «посещенный», а затем переходите к его дочерним элементам. Если вы когда-либо видели узел с установленным флажком «visted», вы знаете, что есть цикл.

Если модификация графика для включения «посещенного» бита невозможна, вместо него можно использовать набор указателей узлов. Чтобы пометить узел как посещенный, вы поместите в него указатель в наборе. Если указатель уже находится в наборе, есть цикл.

+0

Это решение аналогично решению KennyTM, но это лучше. Проблема состоит в том, чтобы идентифицировать циклы, поэтому метка и прокрутка - хороший подход. Построение остовного дерева, как было предложено KennyTM, является более сложным способом решения проблемы, поскольку вы используете концепцию spanning tree. В конце концов, это почти все равно. – darlinton

+3

@Rakis: Будет ли это неверно идентифицировать http://en.wikipedia.org/wiki/File:Diamond_inheritance.svg как цикл? – kennytm

+0

@KennyTM: Да, будет. И неважно, используете ли вы DFS или BFS для изучения узлов на графике - вы получите одинаковый неверный ответ в любом случае. Недостаточно отслеживать, какие узлы были посещены, чтобы идентифицировать циклы. Поэтому я бы вычитал точку для ответа Ракиса (но моя репутация слишком скудна для этого). – Peter

16

Что вам действительно нужно, я считаю, является топологическим алгоритм сортировки, как описан здесь:

http://en.wikipedia.org/wiki/Topological_sorting

Если ориентированный граф имеет цикл, то алгоритм не удастся.

Замечания/ответы, которые я видел до сих пор, похоже, отсутствуют, поскольку в диаграмме , направленной, может быть более одного способа получить от узла X до узла Y без наличия (направленного) циклов на графике.

1

подход: 1
как насчет уровня нет назначения для обнаружения цикла. например: рассмотрим график ниже. A -> (B, C) B-> D D -> (E, F) E, F -> (G) E-> D Как вы запускаете DFS, назначая уровень no узлу, который вы посещаете (root A = 0). level no узла = parent + 1. Итак, A = 0, B = 1, D = 2, F = 3, G = 4, тогда рекурсия достигает D, поэтому E = 3. Dont отметьте уровень для G (G уже не присвоен уровень, который больше, чем E). Теперь E также имеет преимущество до D. Таким образом, выравнивание говорит, что D должен получить уровень no 4. Но D уже имеет «нижний уровень» к нему из 2. Таким образом, в любое время, когда вы пытаетесь присвоить номер уровня узлу при выполнении DFS, который уже имеет более низкий уровень, установленный на нем, вы знаете, что ориентированный график имеет цикл.

approach2:
используйте 3 цвета. белый, серый, черный. цвет только белые узлы, белые узлы до серого, когда вы идете вниз по DFS, цвет серых узлов до черного, когда рекурсия разворачивается (все дети обрабатываются). если не все дети еще обработаны, и вы попадаете в серый узел, в котором есть цикл. например: все белые, чтобы начать в прямом графике. Цвет A, B, D, F, G окрашены в белый цвет. G - лист, поэтому все дети обработали цвет серым до черного. рекурсия разворачивается до F (все обработанные дети) цвет черный. теперь вы достигаете D, D имеет необработанных детей, поэтому цвет E серый, G уже окрашен в черный цвет, поэтому не идет дальше. E также имеет кромку D, поэтому, продолжая обрабатывать D (D еще серый), вы обнаруживаете, что край возвращается к D (серый узел), обнаружен цикл.

0

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

2

Использование DFS для поиска, если любой путь циклическая

class Node<T> { T value; List<Node<T>> adjacent; } 

class Graph<T>{ 

    List<Node<T>> nodes; 

    public boolean isCyclicRec() 
    { 

     for (Node<T> node : nodes) 
     { 
      Set<Node<T>> initPath = new HashSet<>(); 
      if (isCyclicRec(node, initPath)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

    private boolean isCyclicRec(Node<T> currNode, Set<Node<T>> path) 
    { 
     if (path.contains(currNode)) 
     { 
     return true; 
     } 
     else 
     { 
     path.add(currNode); 
     for (Node<T> node : currNode.adjacent) 
     { 
      if (isCyclicRec(node, path)) 
      { 
       return true; 
      } 
      else 
      { 
       path.remove(node); 
      } 
     } 
     } 
     return false; 
    } 
+0

Вы вообще не определили функцию isCyclic. –

+0

этот код не работает на этом входе: 4 -> 1-> 2-> 3. он не работает, если вы начинаете исследовать с узла 1. –

+1

нашел, как исправить: Установите > initPath = new HashSet <>(); должен быть внутри цикла. –

 Смежные вопросы

  • Нет связанных вопросов^_^