问题:
编写一个程序,给出有向图中的循环数。
方法一:
我知道我们可以使用深度优先搜索来检测图中的循环,并以简单的布尔值形式返回答案。我在下面为此编写了代码。但是,我正在尝试在此代码中实现一个计数器,该计数器在每次检测到循环时都会递增。但无论我在哪里实施计数器,我似乎都没有得到正确的答案!(我已经在评论中写了增量语句)
我也担心 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");
}
}