Algorithm to find and print simple cycle in comple

2019-05-11 00:50发布

问题:

Given graph G(V,E), un-directed graph.

|E| = m, |V| = n 

The graph's data structure is Adjacency list

How to find and print simple cycle (or print that there is no such cycle) in complexity of O(n)?
(If there is cycle the output should be the list of vertex that are part of the cycle.)

I know how to find cycle on complexity of O(n), there is also gudies on the internet.
My problem is how to print it.

This is what I tried to do:

DFS-CheckCycle ( Graph G)
{
    p[] <- null //parent array
    foreach v in V
        Color[u] <- white

    foreach v in V
    {
        if (Color[u] = white) 
            Visit(u)
    }
}

Visit(Vertex u)
{
    bool Cycle <- false;
    Color[u] <- gray
    foreach v in Adj[u]
    {
        p[v] <- u
        if (Color[v] = white)
            Visit(v);
        else if (Color[v] = gray) 
        {
            Cycle <- true;
            break;
        }
    }

    if(!Cycle)
        print "No Cycle"
    else
        PrintCycle(v,u)
}



PrintCycle(Vertex v, Vertex u)
{
    if(v = u)
        print v;
    else
    {
        print v;
        PrintCycle(p[v], u);
    }
}

remember that it needs to be O(n).
My PrintCycle function doesn't print all the vertexes.

I need some help how to print the vertexes of the cycle I found.

回答1:

I noticed two things which does not seem correct in your algorithm. Firstly, when you use your DFS walk, you should maintain the following invariant:

  1. Unvisited vertices should be painted white; (you did that)
  2. Visited vertices, for which Visit() hasn't ended yet, should be painted gray;
  3. Visited vertices, for which Visit() has returned should be painted black(or color, other than gray or white).

The other thing I noticed, you don't assign parents for nodes correctly. In your Visit() method parents are assigned even if the vertex we want to visit on the next step is gray, i.e. already has a parent in DFS-tree.

So I would change your code accordingly:

DFS-CheckCycle ( Graph G)
{
    p[] <- null //parent array
    foreach v in V
        Color[v] <- white

    foreach u in V
    {
        if (Color[u] = white) {
            p[u] <- -1; // meaning it is a root of a DFS-tree of the DFS forest
            Visit(u)
        }
    }
}

Visit(Vertex u)
{
    bool Cycle <- false;
    Color[u] <- gray
    foreach v in Adj[u]
    {
        if (Color[v] = white) {
            p[v] <- u
            Visit(v);
        }
        else if (Color[v] = gray) 
        {
            Cycle <- true;
            break;
        }
    }
    Color[u] <- black; // once DFS for this vertex ends, assign its color to black

    if(!Cycle)
        print "No Cycle"
    else
        PrintCycle(v,u)
}



PrintCycle(Vertex v, Vertex u)
{
    if(v = u)
        print v;
    else
    {
        print v;
        PrintCycle(p[v], u);
    }
}

EDIT: It might be a good idea to turn your PrintCycle method into non-recursive one:

PrintCycle(Vertex v, Vertex u) 
{
    do {
        print u;
        u = p[u];
    } while (u != v);
}


回答2:

In the recursive search, you can add a parameter that is a chain of ancestors all the way to the search root. The cycle will consist of the current node and those in the chain ending at the gray node found to discover the cycle.

By chain I mean a lisp-style list: a pair consisting of a node and another pair, the final pair being null.

A more straightforward way is to search with an explicit stack rather than recursion. The Nodes on the stack are all gray. When you find a gray node indicating cycle, the cycle can be printed by working backward through the stack.