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

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


person iva123    schedule 26.03.2010    source источник
comment
возможный дубликат Как проверить, является ли ориентированный граф ацикличный?   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 14.01.2015
comment
Я только что опубликовал общее решение FP для Scala в связанном потоке StackOverflow: stackoverflow.com/a/36144158/501113   -  person chaotic3quilibrium    schedule 22.03.2016
comment
См. Мой ответ здесь: stackoverflow.com/a/60196714/1763149   -  person Marcin Raczyński    schedule 13.02.2020


Ответы (6)


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

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

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

person kennytm    schedule 26.03.2010
comment
BFS или DFS имеют одинаковую сложность (время выполнения) и применимость (одинаковый результат) для решения этой проблемы. Единственная разница заключается в порядке посещения узлов. - person darlinton; 26.03.2010
comment
Последнее утверждение на странице, указанное в ссылке, является топологическим утверждением, основанным на количестве ребер и вершин: Максимальное количество возможных ребер в графе G, если он не имеет цикла, равно | V | - 1. Это верно для неориентированных графов, но не для ориентированных графов, как указано в исходном вопросе. Для ориентированных графов ромбовидная диаграмма наследования дает контрпример (4 узла и 4 ребра образуют цикл, но не цикл, который можно пройти, следуя стрелкам). - person Peter; 29.03.2010
comment
В случае, если последний комментарий не был ясен - я говорю, что принятый ответ достаточен для неориентированных графов, но неправильный для ориентированных графов (как указано в вопросе). - person Peter; 29.03.2010
comment
@Peter: Предыдущая ссылка может быть неправильной, но концепция, которую я описал, верна даже для орграфов. Я уточнил терминологию и предоставил лучший источник. - person kennytm; 29.03.2010
comment
@darlinton: но делать BFS - перебор, потому что того же можно добиться с помощью гораздо более простого DFS. - person Lazer; 05.04.2010
comment
Образец цитирования: Введение в алгоритмы CLRS, 3-е издание, стр. 604-610. - person Nathan; 08.06.2012

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

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

Если у ориентированного графа есть цикл, алгоритм не сработает.

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

person Peter    schedule 29.03.2010

Используйте 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;
  }
person Abhijeet Kushe    schedule 15.08.2014
comment
Вы вообще не определили функцию isCyclic. - person Hopeful Llama; 04.12.2015
comment
этот код не работает на этом входе: 4 - ›1-› 2- ›3. он потерпит неудачу, если вы начнете исследование с узла 1. - person Sayat Satybald; 03.07.2016
comment
нашел как исправить: Установить ‹Node ‹T›› initPath = new HashSet ‹› (); должен быть внутри цикла for. - person Sayat Satybald; 03.07.2016

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

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

person Abhishek    schedule 06.04.2012

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

person kdperspective    schedule 11.12.2013

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

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

person Rakis    schedule 26.03.2010
comment
это решение похоже на решение, предлагаемое Kenny TM, но оно лучше решает проблему. Проблема состоит в том, чтобы идентифицировать циклы, поэтому отметка и очистка - хороший подход. Построение связующего дерева, предложенное КенниTM, является более сложным способом решения проблемы, поскольку вы используете концепцию связующего дерева. В конце концов, это почти все то же самое. - person darlinton; 26.03.2010
comment
@Rakis: Будет ли он неправильно идентифицировать en.wikipedia.org/wiki/File:Diamond_inheritance.svg как цикл? - person kennytm; 26.03.2010
comment
@KennyTM: Да, будет. И неважно, используете ли вы DFS или BFS для исследования узлов на графике - в любом случае вы получите один и тот же неверный ответ. Недостаточно отслеживать, какие узлы были посещены, чтобы идентифицировать циклы. Так что я бы вычел один балл за ответ Ракиса (но моя репутация слишком мала для этого). - person Peter; 29.03.2010
comment
Ах, действительно было бы. Полагаю, я думал о дереве, а не о реальном графике. Однако я считаю, что тот же общий подход будет работать и в этом случае, отслеживая посещенные ребра, а не посещенные узлы. Использование набора пар (from_node_id, to_node_id) обнаружит пересечение одного и того же ребра более одного раза. - person Rakis; 01.04.2010
comment
Правильное решение содержит отметку и развертку, но требует трех цветов. Вы помечаете непосещенные узлы белым, посещаемые узлы серым, а узлы, которые являются корнем полностью посещенного подграфа, черным. См. personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms / GraphAlgor / - person Nathan; 08.06.2012