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