英文:
Should D. B. Johnson's "elementary circuits" algorithm produce distinct results?
问题
Johnson的论文首先描述了有向图中的不同的基本电路(简单循环):
如果除了第一个和最后一个顶点外,没有其他顶点出现两次,那么电路就是基本的。如果一个基本电路不是另一个基本电路的循环排列,那么它们就是不同的。图G中有c个不同的基本电路。
我试图拼凑出一些类似伪代码的东西,有点借鉴了networkx和这个Java实现。但是我似乎没有得到不同的基本电路。
这是我的代码。它使用了goraph库,但除了获取强连通分量之外,没有做太多其他事情。
package main
import (
"fmt"
"github.com/gyuho/goraph/algorithm/scc/tarjan"
"github.com/gyuho/goraph/graph/gs"
)
func main() {
gr := gs.NewGraph()
a := gr.CreateAndAddToGraph("A")
b := gr.CreateAndAddToGraph("B")
c := gr.CreateAndAddToGraph("C")
d := gr.CreateAndAddToGraph("D")
e := gr.CreateAndAddToGraph("E")
f := gr.CreateAndAddToGraph("F")
gr.Connect(a, b, 1)
gr.Connect(b, c, 1)
gr.Connect(c, a, 1)
gr.Connect(d, e, 1)
gr.Connect(e, f, 1)
gr.Connect(f, d, 1)
sccs := tarjan.SCC(gr) // 返回[][]string
for _, scc := range sccs {
if len(scc) < 3 {
continue
}
for _, v := range scc {
n := node(v)
circuit(n, n, gr)
}
}
fmt.Println(result)
}
type node string
var blocked = make(map[node]bool)
var B = make(map[node][]node)
var path []node
var result [][]node
func circuit(thisNode node, startNode node, g *gs.Graph) bool {
closed := false
path = append(path, thisNode)
blocked[thisNode] = true
adj := g.FindVertexByID(string(thisNode)).GetOutVertices().GetElements()
for _, next := range adj {
nextNode := node(next.(*gs.Vertex).ID)
if nextNode == startNode {
cycle := []node{}
cycle = append(cycle, path...)
cycle = append(cycle, startNode)
result = append(result, cycle)
closed = true
} else if !blocked[nextNode] {
if circuit(nextNode, startNode, g) {
closed = true
}
}
}
if closed {
unblock(thisNode)
} else {
adj = g.FindVertexByID(string(thisNode)).GetOutVertices().GetElements()
for _, next := range adj {
nextNode := node(next.(*gs.Vertex).ID)
inB := false
for _, v := range B[nextNode] {
if v == thisNode {
inB = true
}
}
if !inB {
B[nextNode] = append(B[nextNode], thisNode)
}
}
}
path = path[:len(path)-1]
return closed
}
func unblock(thisNode node) {
stack := []node{thisNode}
for len(stack) > 0 {
n := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if blocked[n] {
blocked[n] = false
stack = append(stack, B[n]...)
B[n] = []node{}
}
}
}
这是输出结果:
[[C A B C] [B C A B] [A B C A] [F D E F] [E F D E] [D E F D]]
对我来说,图论是一个充满魔力的神秘黑暗森林,所以我不确定我漏掉了什么。我是否误读了论文?是否暗示应该以其他方式过滤掉冗余的排列?我的代码出了问题吗?
英文:
Johnson's paper starts out describing distinct elementary circuits (simple cycles) in a directed graph:
>A circuit is elementary if no vertex but the first and last appears twice. Two elementary circuits are distinct if one is not a cyclic permutation of the other. There are c distinct elementary circuits in G
I tried to cobble together something vaguely resembling the pseudo code, kind of badly cheating off of networkx and this Java implementation. I am apparently not getting distinct elementary circuits.
This is my code. It uses the goraph library, but doesn't really do too much with it, besides getting strongly connected components.
package main
import (
"fmt"
"github.com/gyuho/goraph/algorithm/scc/tarjan"
"github.com/gyuho/goraph/graph/gs"
)
func main() {
gr := gs.NewGraph()
a := gr.CreateAndAddToGraph("A")
b := gr.CreateAndAddToGraph("B")
c := gr.CreateAndAddToGraph("C")
d := gr.CreateAndAddToGraph("D")
e := gr.CreateAndAddToGraph("E")
f := gr.CreateAndAddToGraph("F")
gr.Connect(a, b, 1)
gr.Connect(b, c, 1)
gr.Connect(c, a, 1)
gr.Connect(d, e, 1)
gr.Connect(e, f, 1)
gr.Connect(f, d, 1)
sccs := tarjan.SCC(gr) // returns [][]string
for _, scc := range sccs {
if len(scc) < 3 {
continue
}
for _, v := range scc {
n := node(v)
circuit(n, n, gr)
}
}
fmt.Println(result)
}
type node string
var blocked = make(map[node]bool)
var B = make(map[node][]node)
var path []node
var result [][]node
func circuit(thisNode node, startNode node, g *gs.Graph) bool {
closed := false
path = append(path, thisNode)
blocked[thisNode] = true
adj := g.FindVertexByID(string(thisNode)).GetOutVertices().GetElements()
for _, next := range adj {
nextNode := node(next.(*gs.Vertex).ID)
if nextNode == startNode {
cycle := []node{}
cycle = append(cycle, path...)
cycle = append(cycle, startNode)
result = append(result, cycle)
closed = true
} else if !blocked[nextNode] {
if circuit(nextNode, startNode, g) {
closed = true
}
}
}
if closed {
unblock(thisNode)
} else {
adj = g.FindVertexByID(string(thisNode)).GetOutVertices().GetElements()
for _, next := range adj {
nextNode := node(next.(*gs.Vertex).ID)
inB := false
for _, v := range B[nextNode] {
if v == thisNode {
inB = true
}
}
if !inB {
B[nextNode] = append(B[nextNode], thisNode)
}
}
}
path = path[:len(path)-1]
return closed
}
func unblock(thisNode node) {
stack := []node{thisNode}
for len(stack) > 0 {
n := stack[len(stack)-1]
stack = stack[:len(stack)-1]
if blocked[n] {
blocked[n] = false
stack = append(stack, B[n]...)
B[n] = []node{}
}
}
}
This is the output:
[[C A B C] [B C A B] [A B C A] [F D E F] [E F D E] [D E F D]]
Graph theory is a spooky, dark forest full of magic for me, so I'm not sure what I'm missing. Am I misreading the paper? Is it implied that redundant permutations should be filtered out some other way? Did I screw up the code?
答案1
得分: 2
冗余的排列被过滤掉,因为每个返回排列的起始节点始终小于所有剩余的元素(根据某种排序)。
我怀疑问题出在缺少实现以下步骤:
> AK:强连通分量K的邻接结构,其中最小顶点在由{s,s + 1,n}诱导的G的子图中;
和
> s:V中最小的顶点;
这些步骤应该确保每个排列的起始点(s)始终小于排列的其余部分,但我看不到实现这一点的代码,相反,你似乎在强连通分量中循环遍历每个节点。
英文:
The redundant permutations are filtered out because the start node of each returned permutation is always less than all the remaining elements (under some ordering).
I suspect the problem is in a missing implementation of these steps:
> AK:= adjacency structure of strong component K with least vertex in
> subgraph of G induced by {s, s+ 1, n};
and
> s := least vertex in V;
These steps should ensure that the start of each permutation (s) is always less than the rest of the permutation but I cannot see code to implement this, instead you seem to loop through every node in the strongly connected component.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论