4

Given a graph G = (V, E), using DFS, how do I label each edge with the number of simple cycles it participates in? I am already labeling the nodes with a post-order when I extract the strongly connected components from the graph, so maybe I can use that information somehow.

private Integer labelEdges(Node currentNode, Set<Node> component) {

    Integer numLoops = 0;
    currentNode.onStack = true;

    for (Edge outEdge : currentNode.getEdges()) {
        Node nextNode = outEdge.getEnd();
        if (component.contains(nextNode)) {
            if (nextNode.onStack) {
                // loop
                numLoops += 1;
            }
            else {
                numLoops += labelEdges(nextNode, component);
            }
            outEdge.cycles = numLoops;
        }

    }
    currentNode.onStack = false;

    return numLoops;
}

I can't seem to reason clearly about this. Can anyone point me in the right direction?

Aidenhjj
  • 1,249
  • 1
  • 14
  • 27
  • 1
    ...if you are the "owner" of `Edge`, then you could (simply) introduce an instance variable on it. (e.g. `numOfCircles`) ... and increment it in your DFS ...as you see fit. (if not...you can create&maintain a `Map`) – xerx593 Dec 04 '18 at 11:06

2 Answers2

4

It is hard to give you a complete answer without seeing your whole code, but I think this will help. Note that the links provided are for undirected graphs.

I think you should divide the problem in two:

1. Finding all the cycles in a graph (save them on a hash-table or similar)

2. Finding which of those cycles contain certain node.

Solution for 1: For the first step there are a lot of algorithms on-line, like this one that would work with minor tweaks or this one that counts the number of cycles and you can change it to save the cycles it finds.

Solution for 2: This depends on how you save the cycles, but it's a simple search algorithm.

Note that this solution is not optimal if you only want to find the answer for one node one time, but it is really good if you want to be able to find the number of cycles for any given node and any given time.

Josef Ginerman
  • 1,460
  • 13
  • 24
0

I ended up adding an extra Map<Node, Stack<Edge>> of previousEdges, to keep track of which edge to traverse back up in the backtrack. The unwindStack function then traverses this linked list, incrementing the Edge.cycles until it gets to the Node that ended the loop (loopNode):

private void labelEdges(Node currentNode, Set<Node> component) {

    onStack.put(currentNode, Boolean.TRUE);

    for (Edge outEdge : currentNode.getEdges()) {
        Node nextNode = outEdge.getEnd();
        if (component.contains(nextNode)) {

            // put the edge on the previousEdges stack
            if (!previousEdges.containsKey(nextNode)) {
                previousEdges.put(nextNode, new Stack<>());
            }
            previousEdges.get(nextNode).push(outEdge);

            if (onStack.getOrDefault(nextNode, false)) {
                // found loop
                unwindStack(nextNode, nextNode);
                // pop the previousEdge off the stack, so that we undo any
                // overwriting of history for another branch.
                previousEdges.get(nextNode).pop();

            }
            else {
                // recursively call this function
                labelEdges(nextNode, component);
            }
        }
    }
    onStack.put(currentNode, Boolean.FALSE);
}

private void unwindStack(Node currentNode, Node loopNode) {
    Edge previousEdge;
    try {
        previousEdge = previousEdges.get(currentNode).peek();
    } catch (EmptyStackException e) {
        previousEdge = null;
    }
    if (previousEdge != null) {
        // increment edgeCycles entry by 1
        edgeCycles.merge(previousEdge, 1, Integer::sum);
        Node previousNode = previousEdge.getStart();
        if (previousNode != loopNode) {
            unwindStack(previousNode, loopNode);
        }
    }
}
Aidenhjj
  • 1,249
  • 1
  • 14
  • 27