๐ง DAG : Directed Acyclic Graph
DAG๋ Cycle์ด ์๋ ๋ฐฉํฅ ๊ทธ๋ํ๋ฅผ ์๋ฏธํฉ๋๋ค.
๋ฐฉํฅ ๊ทธ๋ํ $G$ ์์ Cycle์ด ์๋ค๋ ๊ฒ์, $G$ ์ ๋ํ DFS Tree๊ฐ Back Edge๋ฅผ ๊ฐ์ง๊ณ ์์ง ์๋ค๋ ๋ง๊ณผ ๋์ผํฉ๋๋ค.
๐ ์ฆ๋ช
๐ง ์์ ์ ๋ ฌ(Topological Sort)
์์ ์ ๋ ฌ์ ์์๊ฐ ์ ํด์ ธ์๋ ์์ ์ ์ฐจ๋ก๋ก ์ํํด์ผ ํ ๋ ๊ทธ ์์๋ฅผ ๊ฒฐ์ ํด์ฃผ๊ธฐ ์ํด ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค.
์์ ์ ๋ ฌ์ ์ค์ง DAG ์์๋ง ์ํ๋ ์ ์์ต๋๋ค.
์์ ์ ๋ ฌ์์์ ์ ๋ ฌ ๊ธฐ์ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๊ฐ์ $($ $u$, $v$ $)$ ๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ(์ฆ $u$ ์์ $v$ ๋ก์ edge๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ),
์ ์ $u$ ๋, ์ ์ $v$ ๋ณด๋ค ์์๊ฐ ์์ ๋๋ค.
์๋ฅผ ๋ค์ด ์ ๊ทธ๋ํ์์ ์์ ์ ๋ ฌ์ ์ํํ ๊ฒฐ๊ณผ๋
$5, 3, 1, 2, 4$ ์ ๋๋ค.
์์ ์ ๋ ฌ์ DFS๋ฅผ ํตํด ์ํ๋ ์ ์์ผ๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ํ ๊ฐ๋ฅํฉ๋๋ค.
DFS Tree์ ๊ฐ node $v$ ์ ๋ํด, $post(v)$ ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ด๋ฆผ์ฐจ์(Decreasing Order) ์ ๋ ฌํ๋ฉด,
ํด๋น ์ ๋ ฌ์ ๊ฒฐ๊ณผ๋ ์์ ์ ๋ ฌ์ ๊ฒฐ๊ณผ๊ฐ ๋ฉ๋๋ค.
๋๋ Stack์ ์ฌ์ฉํ๋ฉด ๋ฐ๋ก ์ ๋ ฌํ์ง ์๊ณ ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
DFS๋ฅผ ์ํํ๋ฉฐ postVisit($v$)๋ฅผ ํ ๋๋ง๋ค, $v$ ๋ฅผ Stack์ push ํฉ๋๋ค.
์ดํ DFS๊ฐ ๋ชจ๋ ์ข ๋ฃ๋๋ฉด Stack ์์ ์ฐจ๋ก๋๋ก Pop ํด์ฃผ๋ฉด, ๊ทธ๊ฒ์ด ์์ ์ ๋ ฌ์ ๊ฒฐ๊ณผ๊ฐ ๋ฉ๋๋ค.
Kahn's Algorithm์ด๋ผ๋ BFS๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค.
๊ทธ๋ํ์ Source(InDegree๊ฐ 0)๋ค ์ค ํ๋๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
์ดํ ํด๋น Graph์์ ์ถ๋ ฅํ Source๋ฅผ ์ ๊ฑฐํ ๋ค, ๋๋จธ์ง Graph์ ๋ํ์ฌ ๊ฐ์ ๊ณผ์ ์ ์ฌ๊ท์ ์ผ๋ก ๋ฐ๋ณตํฉ๋๋ค.
์ด๋ ๊ทธ๋ํ์ Vertex๊ฐ ์กด์ฌํ์ง ์์ ๋๊น์ง ๋ฐ๋ณต๋ฉ๋๋ค.
ํด๋น ๊ณผ์ ์ ๋ค์ ๋ธ๋ก๊ทธ์์ ์์ธํ ์ค๋ช ๋์ด ์์ต๋๋ค.
๐ง ์์ ๋ฌธ์
https://www.acmicpc.net/problem/2252
์ ๋ฌธ์ ๋ฅผ ์์ ์ ๋ ฌ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
๐ ํด๋ต
Stack์ ์ฌ์ฉํ์ง ์๊ณ PostOrder๋ฅผ ๋ด๋ฆผ์ฐจ์ํ์ฌ ํด๊ฒฐํ ํ์ด
import java.io.BufferedReader
import java.io.InputStreamReader
/**
* Created by ShinD on 2022/09/24.
*/
fun main() {
val br = BufferedReader(InputStreamReader(System.`in`))
val numOfVertexAndEdge = br.readLine().split(" ")
val vertexCount = numOfVertexAndEdge[0].toInt()
val edgeCount = numOfVertexAndEdge[1].toInt()
// Vertex ๋ฑ๋ก
val vertexes = mutableListOf<Vertex>()
for (i in 0 until vertexCount) {
vertexes.add(Vertex(i + 1))
}
val graph = Graph(vertexCount)
for (i in 0 until edgeCount) {
val edge = br.readLine().split(" ")
graph.addEdge(vertexes[edge[0].toInt()-1], vertexes[edge[1].toInt() - 1])
}
GraphExplorer().dfsInAllGraph(graph, vertexes)
vertexes.sortByDescending { it.postOrder }
vertexes.forEach { print("${it.value} ") }
}
class Vertex(
val value: Int,
var preOrder: Int = 0,
var postOrder: Int = 0,
var isVisited: Boolean = false,
)
class Graph(
vertexCount: Int,
) {
val graph: MutableList<MutableList<Vertex>> = mutableListOf()
init {
for (i in 0 until vertexCount) {
graph.add(mutableListOf())
}
}
fun addEdge(
start: Vertex,
end: Vertex,
) {
graph[start.value - 1].add(end)
}
}
class GraphExplorer {
var counter = 1
fun dfsInAllGraph(graph: Graph, vertexes: MutableList<Vertex>) {
vertexes.forEach {
if(!it.isVisited) dfs(graph, it)
}
}
private fun dfs(graph: Graph, current: Vertex) {
preVisit(current)
current.isVisited = true
graph.graph[current.value - 1]
.forEach {
if (!it.isVisited) dfs(graph, it)
}
postVisit(current)
}
private fun preVisit(current: Vertex) {
current.preOrder = counter++
}
private fun postVisit(current: Vertex) {
current.postOrder = counter++
}
}
Stack์ ์ฌ์ฉํ ํ์ด
import java.io.BufferedReader
import java.io.InputStreamReader
/**
* Created by ShinD on 2022/09/24.
*/
fun main() {
val br = BufferedReader(InputStreamReader(System.`in`))
val numOfVertexAndEdge = br.readLine().split(" ")
val vertexCount = numOfVertexAndEdge[0].toInt()
val edgeCount = numOfVertexAndEdge[1].toInt()
// Vertex ๋ฑ๋ก
val vertexes = mutableListOf<Vertex>()
for (i in 0 until vertexCount) {
vertexes.add(Vertex(i + 1))
}
val graph = Graph(vertexCount)
for (i in 0 until edgeCount) {
val edge = br.readLine().split(" ")
graph.addEdge(vertexes[edge[0].toInt()-1], vertexes[edge[1].toInt() - 1])
}
val stack = ArrayDeque<Vertex>()
GraphExplorer().dfsInAllGraph(graph, vertexes, stack)
// vertexes.sortByDescending { it.postOrder }
// vertexes.forEach { print("${it.value} ") }
while (stack.isNotEmpty()) {
print("${stack.removeLast().value} ")
}
}
class Vertex(
val value: Int,
var preOrder: Int = 0,
var postOrder: Int = 0,
var isVisited: Boolean = false,
)
class Graph(
vertexCount: Int,
) {
val graph: MutableList<MutableList<Vertex>> = mutableListOf()
init {
for (i in 0 until vertexCount) {
graph.add(mutableListOf())
}
}
fun addEdge(
start: Vertex,
end: Vertex,
) {
graph[start.value - 1].add(end)
}
}
class GraphExplorer {
var counter = 1
fun dfsInAllGraph(
graph: Graph,
vertexes: MutableList<Vertex>,
stack: ArrayDeque<Vertex>
) {
vertexes.forEach {
if(!it.isVisited) dfs(graph, it, stack)
}
}
private fun dfs(
graph: Graph,
current: Vertex,
stack: ArrayDeque<Vertex>
) {
preVisit(current)
current.isVisited = true
graph.graph[current.value - 1]
.forEach {
if (!it.isVisited) dfs(graph, it, stack)
}
postVisit(current)
stack.addLast(current)
}
private fun preVisit(current: Vertex) {
current.preOrder = counter++
}
private fun postVisit(current: Vertex) {
current.postOrder = counter++
}
}
Kahn's Algorithm ์ฌ์ฉ
import java.io.BufferedReader
import java.io.InputStreamReader
/**
* Created by ShinD on 2022/09/24.
*/
fun main() {
val br = BufferedReader(InputStreamReader(System.`in`))
val numOfVertexAndEdge = br.readLine().split(" ")
val vertexCount = numOfVertexAndEdge[0].toInt()
val edgeCount = numOfVertexAndEdge[1].toInt()
// Vertex ๋ฑ๋ก
val vertexes = mutableListOf<Vertex>()
for (i in 0 until vertexCount) {
vertexes.add(Vertex(i + 1))
}
val graph = Graph(vertexCount)
for (i in 0 until edgeCount) {
val edge = br.readLine().split(" ")
graph.addEdge(vertexes[edge[0].toInt()-1], vertexes[edge[1].toInt() - 1])
}
val stack = ArrayDeque<Vertex>()
GraphExplorer().topologySortByQueue(graph, vertexes)
}
class Vertex(
val value: Int,
var isVisited: Boolean = false,
var inDegree: Int = 0,
)
class Graph(
vertexCount: Int,
) {
val graph: MutableList<MutableList<Vertex>> = mutableListOf()
init {
for (i in 0 until vertexCount) {
graph.add(mutableListOf())
}
}
fun addEdge(
start: Vertex,
end: Vertex,
) {
graph[start.value - 1].add(end)
end.inDegree ++
}
}
class GraphExplorer {
fun topologySortByQueue(
graph: Graph,
vertexes: MutableList<Vertex>,
) {
val queue = ArrayDeque<Vertex>()
val vertexCount = graph.graph.size
for (i in 0 until vertexCount) {
if (vertexes[i].inDegree == 0) queue.addLast(vertexes[i])
}
for (i in 0 until vertexCount) {
// ์ ์ ์ ๋ชจ๋ ๋ฐฉ๋ฌธํ๊ธฐ ์ ์ ํ๊ฐ ๋น๋ค๋ฉด ์ฌ์ดํด์ด ๋ฐ์ํ ๊ฒ
if (queue.isEmpty()){
println("CYCLE!!")
return
}
val vertex = queue.removeFirst()
print("${vertex.value} ")
for (i in 0 until graph.graph[vertex.value - 1].size) {
val vertex1 = graph.graph[vertex.value - 1][i]
if(--vertex1.inDegree == 0) {
queue.addLast(vertex1)
}
}
}
}
}