用它参与的循环数标记边
Label an edge with number of cycles it participates in
给定一个图 G = (V, E)
,使用 DFS,我如何用它参与的简单循环数来标记每条边?当我从图中提取强连通分量时,我已经用 post-order 标记了节点,所以也许我可以以某种方式使用该信息。
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;
}
这个我好像推理不清楚。谁能指出我正确的方向?
如果没有看到您的完整代码,很难给您一个完整的答案,但我认为这会有所帮助。请注意,提供的链接适用于无向图。
我认为你应该把问题分成两部分:
1. 查找图中的所有循环(将它们保存在散列-table 或类似的)
2. 查找那些循环中的哪些包含特定节点。
1的解决方法:第一步网上有很多算法,比如this one that would work with minor tweaks or this one就是计算循环次数,你可以改保存找到的循环。
2 的解决方案: 这取决于您如何保存循环,但这是一个简单的搜索算法。
请注意,如果您只想一次找到一个节点的答案,则此解决方案不是最佳解决方案,但如果您希望能够找到任何给定节点和任何给定的循环数,则该解决方案非常好时间.
我最终添加了额外的 Map<Node, Stack<Edge>>
of previousEdges
,以跟踪在回溯中要遍历的边。然后 unwindStack
函数遍历这个链表,递增 Edge.cycles
直到它到达结束循环的 Node
(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);
}
}
}
给定一个图 G = (V, E)
,使用 DFS,我如何用它参与的简单循环数来标记每条边?当我从图中提取强连通分量时,我已经用 post-order 标记了节点,所以也许我可以以某种方式使用该信息。
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;
}
这个我好像推理不清楚。谁能指出我正确的方向?
如果没有看到您的完整代码,很难给您一个完整的答案,但我认为这会有所帮助。请注意,提供的链接适用于无向图。
我认为你应该把问题分成两部分:
1. 查找图中的所有循环(将它们保存在散列-table 或类似的)
2. 查找那些循环中的哪些包含特定节点。
1的解决方法:第一步网上有很多算法,比如this one that would work with minor tweaks or this one就是计算循环次数,你可以改保存找到的循环。
2 的解决方案: 这取决于您如何保存循环,但这是一个简单的搜索算法。
请注意,如果您只想一次找到一个节点的答案,则此解决方案不是最佳解决方案,但如果您希望能够找到任何给定节点和任何给定的循环数,则该解决方案非常好时间.
我最终添加了额外的 Map<Node, Stack<Edge>>
of previousEdges
,以跟踪在回溯中要遍历的边。然后 unwindStack
函数遍历这个链表,递增 Edge.cycles
直到它到达结束循环的 Node
(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);
}
}
}