package dag
func StronglyConnectedComponents(g *Graph) [][]Node {
nodes := g.Nodes()
t := tarjan{
nodes: make(map[Node]int, len(nodes)),
lowLink: make(map[Node]int, len(nodes)),
}
for _, n := range g.Nodes() {
if t.nodes[n] == 0 {
t.tarjan(g, n)
}
}
return t.result
}
type tarjan struct {
index int
nodes map[Node]int
lowLink map[Node]int
stack []Node
result [][]Node
}
func (t *tarjan) tarjan(g *Graph, n Node) {
t.visit(n)
for succ := range g.outEdges[n] {
if t.nodes[succ] == 0 {
t.tarjan(g, succ)
t.lowLink[n] = min(t.lowLink[n], t.lowLink[succ])
} else if t.onStack(succ) {
t.lowLink[n] = min(t.lowLink[n], t.nodes[succ])
}
}
if t.lowLink[n] == t.nodes[n] {
var scc []Node
for {
succ := t.pop()
scc = append(scc, succ)
if succ == n {
break
}
}
t.result = append(t.result, scc)
}
}
func (t *tarjan) visit(n Node) {
t.index++
t.nodes[n] = t.index
t.lowLink[n] = t.index
t.push(n)
}
func min(a, b int) int {
if a <= b {
return a
}
return b
}
func (t *tarjan) push(n Node) {
t.stack = append(t.stack, n)
}
func (t *tarjan) pop() Node {
n := len(t.stack)
if n == 0 {
return nil
}
node := t.stack[n-1]
t.stack = t.stack[:n-1]
return node
}
func (t *tarjan) onStack(n Node) bool {
for _, e := range t.stack {
if n == e {
return true
}
}
return false
}