繁体   English   中英

如何在有向图Java中打印每个循环?

[英]How to print each cycle in a directed graph Java?

我很麻烦。 我真的不知道如何修改代码以打印找到的每个循环。 实际上,如果图形包含一个循环,则下面的代码将返回,但是我也想知道所有可能的循环是什么。

例如,下图包含三个循环0-> 2-> 0、0-> 1-> 2-> 0和3-> 3,因此您的函数必须返回true。

// A Java Program to detect cycle in a graph
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

class Graph {
    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<>());
    }

    // This function is a variation of DFSUytil() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclicUtil(int i, boolean[] visited, boolean[] recStack) 
    {
        // Mark the current node as visited and
        // part of recursion stack
        if (recStack[i])
            return true;

        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);
    }

    // Returns true if the graph contains a 
    // cycle, else false.
    // This function is a variation of DFS() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclic() 
    {
        // Mark all the vertices as not visited and
        // not part of recursion stack
        boolean[] visited = new boolean[V];
        boolean[] recStack = new boolean[V];

        // Call the recursive helper function to
        // detect cycle in different DFS trees
        for (int i = 0; i < V; i++)
            if (isCyclicUtil(i, visited, recStack))
                return true;

        return false;
    }

    // Driver code
    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 cycle");
        else
            System.out.println("Graph doesn't "
                                + "contain cycle");
    }
}

非常感谢。

编辑:之前我提到了使用dfs代替bfs的可能性,但是使用dfs可能会产生非最小周期。 (例如,如果存在循环A-> B-> C-> A,并且存在循环A-> B-> A,则它可能会先找到较长的一个,而不会找到第二个,因为节点仅被访问一次)。

按照定义, elementary cycle是一个节点不重复自身的elementary cycle (起始节点除外),因此情况略有不同。 由于提问者(赏金@ExceptionHandler )想要从输出中排除那些循环,因此使用bfs解决了该问题。

对于纯(强力) elementary cycle搜索,将需要不同的路径查找算法。


通用(又称蛮力)实施将需要以下步骤:

  1. 对于有向图g的每个节点n
    找到所有路径(使用bfs )回到n。

    如果两个节点(方向相同)之间存在多条边,则在此步骤中可以忽略它们,因为算法本身应在节点而不是边上工作。 可以在步骤5中将多个边重新引入循环中。

  2. 如果找不到路径,请继续执行步骤1,并添加n + 1

  3. 每个确定的路径都是一个循环
    将它们添加到循环列表中,然后继续执行步骤1和n + 1

  4. 处理完所有节点后,将找到包含所有可能循环的列表(包括排列)。 子周期不可能形成,因为每个节点在bfs期间只能被访问一次。

    在此步骤中,将先前识别的所有排列组合在一起。 每套仅考虑一个球笼。 这可以通过对节点进行排序并删除重复项来完成。

  5. 现在,已经确定了最小的一组循环并可以将其打印出来。
    如果您正在寻找特定于边的循环,则用两个节点各自的边替换两个节点之间的连接。


A->B B->C C->D D->C C->A示例:

Step 1-3: node A
path identified: A,B,C (A->B B->C C->A)
Step 1-3: node B
path identified: B,C,A (B->C C->A A->B)
Step 1-3: node C
path identified: C,A,B (C->A A->B B->C)
path identified: C,D (C->D D->C)
Step 1-3: node D
path identified: D,C (D->C C->D)
Step 4:
Identified as identical after ordering:

Set1:
A,B,C (A->B B->C C->A)
B,C,A (B->C C->A A->B)
C,A,B (C->A A->B B->C)

Set2:
C,D (C->D D->C)
D,C (D->C C->D)

Therefore remaining cycles:
A,B,C (A->B B->C C->A)
C,D (C->D D->C)
Step 5:
Simply printing out the cycles
(Check the bracket expressions for that,
 I simply added them to highlight the relevant edges).

可以在here找到更有效的示例方法来识别基本循环,该示例直接从此answer 如果有人想提出更详细的解释,那么该算法的工作原理完全可以自由选择。

将主要方法修改为:

public static void main(String[] args) {
    String nodes[] = new String[4];
    boolean adjMatrix[][] = new boolean[4][4];

    for (int i = 0; i < 4; i++) {
        nodes[i] = String.valueOf((char) ('A' + i));
    }

    adjMatrix[0][1] = true;
    adjMatrix[1][2] = true;
    adjMatrix[2][3] = true;
    adjMatrix[3][2] = true;
    adjMatrix[2][0] = true;

    ElementaryCyclesSearch ecs = new ElementaryCyclesSearch(adjMatrix, nodes);
    List cycles = ecs.getElementaryCycles();
    for (int i = 0; i < cycles.size(); i++) {
        List cycle = (List) cycles.get(i);
        for (int j = 0; j < cycle.size(); j++) {
            String node = (String) cycle.get(j);
            if (j < cycle.size() - 1) {
                System.out.print(node + " -> ");
            } else {
                System.out.print(node + " -> " + cycle.get(0));
            }
        }
        System.out.print("\n");
    }
}

实现以下目标的期望输出:

A -> B -> C -> A
C -> D -> C

here可以找到有关该方法的详细信息的Donald B. Johnson论文。


暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM