Finding all cycles in a directed graph

前端 未结 17 2158
渐次进展
渐次进展 2020-11-22 05:47

How can I find (iterate over) ALL the cycles in a directed graph from/to a given node?

For example, I want something like this:

A->B->A
A->B         


        
相关标签:
17条回答
  • 2020-11-22 06:02

    The simplest choice I found to solve this problem was using the python lib called networkx.

    It implements the Johnson's algorithm mentioned in the best answer of this question but it makes quite simple to execute.

    In short you need the following:

    import networkx as nx
    import matplotlib.pyplot as plt
    
    # Create Directed Graph
    G=nx.DiGraph()
    
    # Add a list of nodes:
    G.add_nodes_from(["a","b","c","d","e"])
    
    # Add a list of edges:
    G.add_edges_from([("a","b"),("b","c"), ("c","a"), ("b","d"), ("d","e"), ("e","a")])
    
    #Return a list of cycles described as a list o nodes
    list(nx.simple_cycles(G))
    

    Answer: [['a', 'b', 'd', 'e'], ['a', 'b', 'c']]

    0 讨论(0)
  • 2020-11-22 06:03

    http://www.me.utexas.edu/~bard/IP/Handouts/cycles.pdf

    0 讨论(0)
  • 2020-11-22 06:04

    There are two steps (algorithms) involved in finding all cycles in a DAG.

    The first step is to use Tarjan's algorithm to find the set of strongly connected components.

    1. Start from any arbitrary vertex.
    2. DFS from that vertex. For each node x, keep two numbers, dfs_index[x] and dfs_lowval[x]. dfs_index[x] stores when that node is visited, while dfs_lowval[x] = min(dfs_low[k]) where k is all the children of x that is not the directly parent of x in the dfs-spanning tree.
    3. All nodes with the same dfs_lowval[x] are in the same strongly connected component.

    The second step is to find cycles (paths) within the connected components. My suggestion is to use a modified version of Hierholzer's algorithm.

    The idea is:

    1. Choose any starting vertex v, and follow a trail of edges from that vertex until you return to v. It is not possible to get stuck at any vertex other than v, because the even degree of all vertices ensures that, when the trail enters another vertex w there must be an unused edge leaving w. The tour formed in this way is a closed tour, but may not cover all the vertices and edges of the initial graph.
    2. As long as there exists a vertex v that belongs to the current tour but that has adjacent edges not part of the tour, start another trail from v, following unused edges until you return to v, and join the tour formed in this way to the previous tour.

    Here is the link to a Java implementation with a test case:

    http://stones333.blogspot.com/2013/12/find-cycles-in-directed-graph-dag.html

    0 讨论(0)
  • 2020-11-22 06:04

    DFS c++ version for the pseudo-code in second floor's answer:

    void findCircleUnit(int start, int v, bool* visited, vector<int>& path) {
        if(visited[v]) {
            if(v == start) {
                for(auto c : path)
                    cout << c << " ";
                cout << endl;
                return;
            }
            else 
                return;
        }
        visited[v] = true;
        path.push_back(v);
        for(auto i : G[v])
            findCircleUnit(start, i, visited, path);
        visited[v] = false;
        path.pop_back();
    }
    
    0 讨论(0)
  • 2020-11-22 06:05

    Depth first search with backtracking should work here. Keep an array of boolean values to keep track of whether you visited a node before. If you run out of new nodes to go to (without hitting a node you have already been), then just backtrack and try a different branch.

    The DFS is easy to implement if you have an adjacency list to represent the graph. For example adj[A] = {B,C} indicates that B and C are the children of A.

    For example, pseudo-code below. "start" is the node you start from.

    dfs(adj,node,visited):  
      if (visited[node]):  
        if (node == start):  
          "found a path"  
        return;  
      visited[node]=YES;  
      for child in adj[node]:  
        dfs(adj,child,visited)
      visited[node]=NO;
    

    Call the above function with the start node:

    visited = {}
    dfs(adj,start,visited)
    
    0 讨论(0)
  • 2020-11-22 06:06

    In the case of undirected graph, a paper recently published (Optimal listing of cycles and st-paths in undirected graphs) offers an asymptotically optimal solution. You can read it here http://arxiv.org/abs/1205.2766 or here http://dl.acm.org/citation.cfm?id=2627951 I know it doesn't answer your question, but since the title of your question doesn't mention direction, it might still be useful for Google search

    0 讨论(0)
提交回复
热议问题