计算有向图中的循环数

问题描述

问题:

编写一个程序,为我们提供有向图中的循环数。

方法 1:

我知道我们可以使用深度优先搜索来检测图中的循环,并根据简单的布尔值返回答案。我在下面为此编写了代码。但是,我试图在这代码中实现一个计数器,每次检测到一个周期时它都会增加。但无论我在哪里实施计数器,我似乎都没有得到正确的答案! (我已经在评论中写了增量语句)

我也担心 DFS 不是为这个问题选择的正确方法,因为循环之间可能存在一些共同的边缘。

循环检测算法取自:https://www.geeksforgeeks.org/detect-cycle-in-a-graph/

下面给出的代码产生一个输出

enter image description here

对于图表:

enter image description here

(这里说的是 0 个周期,因为注释的计数是递增的)

代码

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

class Graph 
{   
    static int count = 0; //counter initialised
    private final int V;
    private final List<List<Integer>> adj;

    public Graph(int V)
    {
        this.V = V;
        adj = new ArrayList<>(V);
        
        for (int i = 0; i < V; i++)
            adj.add(new LinkedList<>());
    }
    
    private boolean isCyclicUtil(int i,boolean[] visited,boolean[] recStack)
    {
        if (recStack[i])
            return true; //count++;

        if (visited[i])
            return false;
            
        visited[i] = true;

        recStack[i] = true;
        List<Integer> children = adj.get(i);
        
        for (Integer c: children)
            if (isCyclicUtil(c,visited,recStack))
                return true; 
                
        recStack[i] = false;

        return false;
    }

    private void addEdge(int source,int dest) {
        adj.get(source).add(dest);
    }
    
    private boolean isCyclic()
    {
        boolean[] visited = new boolean[V];
        boolean[] recStack = new boolean[V];
        for (int i = 0; i < V; i++)
            if (isCyclicUtil(i,recStack))
                return true; //count++;
        return false;
    }
    
    public static void main(String[] args)
    {
        Graph graph = new Graph(4);
        graph.addEdge(0,1);
        graph.addEdge(0,2);
        graph.addEdge(1,2);
        graph.addEdge(2,0);
        graph.addEdge(2,3);
        graph.addEdge(3,3);
        
        if(graph.isCyclic())
            System.out.println("Graph contains cycles");
        else
            System.out.println("Graph doesn't contains "+count+" cycles");
    }
}

我也想知道我是否可以使用图形着色方法找到解决方案,这是我能够挖掘的 代码来自:https://www.geeksforgeeks.org/detect-cycle-direct-graph-using-colors/

方法 2:

算法:

  • 创建一个递归函数,该函数采用边和颜色数组(这个 也可以作为全局变量保存)

  • 将当前节点标记为 GREY。

  • 遍历所有相邻的节点,如果有一个节点被标记为GRAY则
    返回真,因为循环必然存在。

  • 如果任何相邻的顶点是白色的,则调用递归函数 那个节点。

  • 如果函数返回真。返回真。

  • 如果没有相邻的节点是灰色的或没有返回真,则标记 当前节点为黑色并返回 false。

代码

import java.io.*;
import java.util.*;

class GFG
{

    // A DFS based approach to find if there is a cycle
    // in a directed graph. This approach strictly follows
    // the algorithm given in Clrs book.
    static int WHITE = 0,GRAY = 1,BLACK = 2;

    // Graph class represents a directed graph using
    // adjacency list representation
    static class Graph
    {
            int V;
            LinkedList<Integer>[] adjList;
            
            // Constructor
            Graph(int ver)
            {
                V = ver;
                adjList = new LinkedList[V];
                for (int i = 0; i < V; i++)
                    adjList[i] = new LinkedList<>();
            }
    }

    // Utility function to add an edge
    static void addEdge(Graph g,int u,int v)
    {
            g.adjList[u].add(v); // Add v to u's list.
    }

    // Recursive function to find if there is back edge
    // in DFS subtree tree rooted with 'u'
    static boolean Dfsutil(Graph g,int[] color)
    {
            // GRAY : This vertex is being processed (DFS
            // for this vertex has started,but not
            // ended (or this vertex is in function
            // call stack)
            color[u] = GRAY;
            
            // Iterate through all adjacent vertices
            for (Integer in : g.adjList[u])
            {
                // If there is
                if (color[in] == GRAY)
                    return true;

                // If v is not processed and there is a back
                // edge in subtree rooted with v
                if (color[in] == WHITE && Dfsutil(g,in,color) == true)
                    return true;
            }

            // Mark this vertex as processed
            color[u] = BLACK;
            return false;
    }

    // Returns true if there is a cycle in graph
    static boolean isCyclic(Graph g)
    {
            // Initialize color of all vertices as WHITE
            int[] color = new int[g.V];
            for (int i = 0; i < g.V; i++)
            {
                color[i] = WHITE;
            }

            // Do a DFS traversal beginning with all
            // vertices
            for (int i = 0; i < g.V; i++)
            {
                if (color[i] == WHITE)
                {
                    if(Dfsutil(g,i,color) == true)
                        return true;
                }
            }
            return false;

    }

    // Driver code to test above
    public static void main(String args[])
    {
            // Create a graph given in the above diagram
            Graph g = new Graph(4);
            addEdge(g,1);
            addEdge(g,2);
            addEdge(g,1,2,0);
            addEdge(g,3);
            addEdge(g,3,3);
            if (isCyclic(g))
                System.out.println("Graph contains cycle");
            else
                System.out.println("Graph doesn't contain cycle");
    }
}

解决方法

我认为问题在于单个节点可以是多个圆圈的一部分,并且您在第一个节点之后设置为“已访问”。我会使用 DFS,然后使用回溯算法来找到圈数。

,

我花了一段时间,但我终于找到了使用 DFS 和 Graph 着色方法解决此问题的方法。我仍在努力简化它,但此代码有效!

//Program to count the number of cycles in a Directed Graph.

import java.util.*;
class dir
{

    public static int WHITE = 0,GRAY = 1,BLACK = 2;
    public static int count=0;
    // Graph class represents a directed graph using
    // adjacency list representation
    public static class Graph
    {
            int V;
            LinkedList<Integer>[] adjList;
            @SuppressWarnings("unchecked")
            Graph(int ver)
            {
                V = ver;
                adjList = new LinkedList[V];
                for (int i = 0; i < V; i++)
                    adjList[i] = new LinkedList<>();
            }
    }
    
    //function to add an edge
    public static void addEdge(Graph g,int u,int v)
    {
            g.adjList[u].add(v); 
    }

    // Recursive function to find if there is back edge
    // in DFS subtree tree rooted with 'u'
    public static boolean DFSUtil(Graph g,int[] color)
    {
            color[u] = GRAY;
            // Iterate through all adjacent vertices
            for (Integer in : g.adjList[u])
            {
                // If there is
                if (color[in] == GRAY)
                    return true;
                //If v is not processed and there is a back
                // edge in subtree rooted with v
                if (color[in] == WHITE && DFSUtil(g,in,color) == true)
                    return true;
            }
            // Mark this vertex as processed
            color[u] = BLACK;
            return false;
    }

    // Returns number of cycles.
    public static int isCyclic(Graph g)
    {
            // Initialize color of all vertices as WHITE
            int[] color = new int[g.V];
            for (int i = 0; i < g.V; i++)
            {
                color[i] = WHITE;
            }
            
            // Do a traversal beginning with all vertices
            for (int i = 0; i < g.V; i++)
            {
                if (color[i] == WHITE)
                {
                    if(DFSUtil(g,i,color) == true)
                        count++; 
                }
            }
            return count;

    }

    //Driver Code
    public static void main(String args[])
    {
            //Modify edges accordingly
            Graph g = new Graph(7);
            addEdge(g,1);
            addEdge(g,4,0);
            addEdge(g,3);
            addEdge(g,3,4);
            addEdge(g,1,2,2);
            if (isCyclic(g)>0)
            {
                System.out.println("Cycle detected");
                System.out.println("Graph contains "+count+" cycles");
            }
            else
                {
                System.out.println("Graph doesn't contain cycle");
                }
    }
}