【问题标题】:Count number of cycles in a Directed graph计算有向图中的循环数
【发布时间】:2021-09-23 13:30:21
【问题描述】:

问题:

编写一个程序,给出有向图中的循环数。

方法一:

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

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

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

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

对于图表:

(这里说的是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, visited, 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:

算法:

  • 创建一个接受边缘和颜色数组的递归函数(这个 也可以作为全局变量保存)

  • 将当前节点标记为灰色。

  • 遍历所有相邻节点,如果任何节点标记为灰色,则
    return true 因为循环必然存在。

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

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

  • 如果没有相邻节点是灰色的或没有返回true,则标记 当前节点为 BLACK 并返回 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 u, 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, 0, 1);
            addEdge(g, 0, 2);
            addEdge(g, 1, 2);
            addEdge(g, 2, 0);
            addEdge(g, 2, 3);
            addEdge(g, 3, 3);
            if (isCyclic(g))
                System.out.println("Graph contains cycle");
            else
                System.out.println("Graph doesn't contain cycle");
    }
}

【问题讨论】:

    标签: java graph cycle-detection


    【解决方案1】:

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

    //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 u, 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, 0, 1);
                addEdge(g, 4, 0);
                addEdge(g, 4, 1);
                addEdge(g, 4, 3);
                addEdge(g, 3, 4);
                addEdge(g, 1, 3);
                addEdge(g, 2, 1);
                addEdge(g, 3, 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");
                    }
        }
    }
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 这是有道理的!因此,例如,如果我使用带有回溯算法的 DFS 代码。每次回溯时,我都会增加 count 的值。我说的对吗?
      猜你喜欢
      • 2021-09-21
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      • 1970-01-01
      • 2018-12-27
      • 2021-09-09
      • 2019-03-28
      相关资源
      最近更新 更多