The direction graph and the non-direction graph are judged to have the ring

Source: Internet
Author: User
Tags getv

Recently began to seriously learn the algorithm, with the Sedgewick of the "algorithms". Much of the content is the same as the data structure, the difference is the content of the algorithm more explanation. I often keep track of the difficulties I encounter in learning algorithms and how to solve them.
The problem of judging the existence loop is encountered when learning the topological sort. The problem of judging the ring is divided into the direction graph and the non-direction graph, and I will expound the problem of the non-direction graph and the direction graph Judgment Ring respectively, then compare the difference between them.

First of all, the non-directed graph, the side of the non-directed graph has no direction, or the edge of each graph is bidirectional, that is, u-v equivalent to U->v & V->v. This is helpful in explaining the specific algorithm later.

The most obvious way to solve the loop problem of the graph is to use the depth-first search (Depth Frist) for processing.
First, the depth-first search is an algorithm for traversing graphs.

The depth-first traversal graph is based on a vertex v from the graph: (1) Access vertex v;
(2) starting from the inaccessible adjacency point of V, the depth-first traversal of the graph is carried out, until the vertices with the paths in the diagram are accessed;
(3) If there are still vertices in the graph that are not accessed, the depth-first traversal is performed from an unreachable vertex until all the vertices in the graph have been accessed.

From the description of this algorithm, we can see that the depth-first search is similar to the first-order traversal of the tree, and the binary tree is actually a kind of graph.
The algorithm for depth-first search is given below

public class Searchusedfs {
    Graph g;
    int s;
    Boolean[] marked;
    int count;  Connectivity number public
    Searchusedfs (Graph g, int s) {
        this.g = g;
        marked = new Boolean[g.getv ()];
        THIS.S = s;
        DFS (s);
    }

    public void Dfs (int v) {
        marked[v] = true;
        count++;
        for (int W:g.adj (v)) {
            if (!marked[w])
                DFS (w);
        }
    } 

    public boolean marked (int v) {
        return marked[v];
    }

    public int count () {
        return count;
    }
}

The above code is a deep-first search to solve the connectivity problem, this content is well understood, a depth-first search can only find points connected to the point.
And what does this have to do with the problem of the non-circular graph we are going to discuss? In fact, we can use DFS to judge a ring.
We know that DFS constructs a tree logically when it is traversing the graph, and many people call him a depth-first search tree .
There are 4 kinds of edge tree edges, forward edges, back edges, and cross edges in the search tree.
"Introduction to the algorithm" 334 pages have the exact definition of these 4 kinds of edges, not in this statement.

DFS process, for an edge u->v
VIS[V] = 0, indicating v has not been accessed, V is the first to be discovered, U->v is a tree edge
VIS[V] = 1, indicating that V has been visited, but its descendants have not yet been visited (in the access), and you point to the V-U is a descendant of V, U->v is a back edge, so the back edge is also called the atavistic side
VIS[V] = 2, indicating that V has been visited, and that its descendants have all been visited, u->v this edge may be a cross-border, or forward edge.

And this refers to the edges in the graph, there are actually only two edges in the graph: the tree edge and the back edge. It can be proved that there is no forward edge and cross side. The reason is very simple, if there is a cross or forward edge, then must satisfy U->v and vis[v]=2, and at this time the edge between U and V is a bidirectional edge ( Here is the former said the non-directional edge can be understood as two-way edge, and the V has been accessed, then according to the definition of Dfs, V will be through the U and V side access U, so that there must be no map of the tree and back edge.

The side of the tree is the node that is being accessed, the other side is an unreachable node, so the tree edge is the normal edge, and the other side of the edge is the node being accessed, and the other side is the node being accessed, such as A-b-c-a, where c is being accessed, and a is being accessed (the recursive function is in progress). This means that the back edge is pointing to its parent node, which in this case must be a ring. This is the idea of Dfs judgment ring.
Directly on the code

        DFS, the discovery Loop (returns True) is non-serializable, returns false for
        (int i = 1; I <= n; i++) {
            if (dfscheckcircuit (i)) {if (-)
                return false;
        }

    //Returns True if the loop is found, otherwise the traversal end returns false
    private Boolean dfscheckcircuit (int current) {
        if (Marked[current]) {
            return true;
        }
        Marked[current] = true;
        for (int i = 1; I <= n; i++)
            if (Digraph[current][i]) {
                if (dfscheckcircuit (i)) {
                    return true;
                }
            }
        Marked[current] = false;
        return false;
    }

There are only a few lines of code that you'll see in the back of the forward graph. Here's one thing to note is that marked[] = = True when there must be a ring. Because the previous article said that the tree side will not touch marked[] = = True point, and no map after the tree and back edge, So once you hit the labeled point you can immediately judge the ring.

The graph is similar to the non-direction graph, the biggest difference is that the edges in the graph are unidirectional, which leads to the presence of forward and cross edges in the Dfs tree, and it is not difficult to think of the fact that the two edges on marked[] are the same as the back edge (if you do not understand this, see the previous article on 4 kinds of edges), So this leads to the fact that we cannot guarantee the correct result simply by judging the marked array, because these two edges do not get the ring.
And careful observation will find that the point of the back edge is actually the parent node in the Dfs tree, and DFS is actually a stack to operate the algorithm, in the DFS recursive call stack is exactly the point of the node's ancestors, so we can use this to determine the direction graph of the loop problem.

A directed graph determines if a loop is traversed through a Dfs to any node, if the node has an edge pointing to the ancestor node, then there is a ring, and the currently found ring is from the point of the ancestor power saving to the node's Path + ancestor node, and we need to save the path is exactly in the DFS recursive stack, So we have not only found an algorithm to judge whether there is a ring, but also found the algorithm to find out the point of the loop!

Import Java.util.Stack;
    public class Directedcycle {private boolean[] marked;
    Private boolean[] Instack;
    private int paths[];
    Private Digraph DG;
    private int v;
    Private Boolean hascycle;
    Private stack<integer>[] s;
    private int pos;
        Public Directedcycle (Digraph DG, int v) {marked = new Boolean[dg.getv ()];
        Instack = new Boolean[dg.getv ()];
        paths = new Int[dg.getv ()];
        THIS.DG = DG;
        THIS.V = v;
        s = (stack<integer>[]) New Stack[dg.getv ()];
    DFS (v);

        } public void Dfs (int v) {Marked[v] = instack[v] = true;
                for (int W:dg.adj (v)) {if (!marked[w]) {paths[w] = V; 
            DFS (W);

                } else if (Instack[w]) {hascycle = true;
                S[pos] = new stack<integer> ();
                for (int x = v;x!=w;x=paths[x]) {s[pos].push (x); } s[pos].push (W);
                S[pos++].push (v);
            Hascycle = true;

    }} Instack[v] = false;
        } public static void Main (string[] args) {Digraph dg = new Digraph (5);
        Dg.addedge (0, 1);
        Dg.addedge (1, 2);
        Dg.addedge (2, 0);
        Dg.addedge (3, 4);
        Dg.addedge (2, 3);
        Dg.addedge (4, 1);
        Directedcycle dc = new Directedcycle (DG, 0);
            for (int i = 0;i<dc.pos;i++) {for (int w:dc.s[i]) System.out.print (w + ":");
        System.out.println ();
    } System.out.println (Dc.pos);
 }
}

These two algorithms are in fact a small modification of DFS, it is not difficult to see the complexity of the algorithm and the traditional DFS complexity is the same, O (v+e).

In fact, there is a lot of common ground for the algorithm that has the ring to the direction graph and the non-direction graph. It is the fact that the back edge of the search tree that is generated by DFS is present , and the difference is that there is no forward edge and cross edge in the graph, so marked[v]==true is equivalent to a ring , and a instack array is needed to help determine whether the edge is a back edge. So whether there is a graph or a graph, the same thing is to determine whether the edge is a back edge, but only the information needed is different.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.