0

问题:

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

方法一:

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

我也担心 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:

算法:

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

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

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

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

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

  • 如果没有相邻节点是灰色的或没有返回true,则将当前节点标记为黑色并返回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");
    }
}
4

2 回答 2

1

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

于 2021-07-14T15:15:29.553 回答
0

我花了一段时间,但我终于找到了使用 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");
                }
    }
}
于 2021-08-09T13:17:42.857 回答