코틀린 코딩테스트 강좌, 다익스트라

문제 설명

그래프가 주어지고, 한 정점에서 다른 정점까지의 최단 경로를 찾는 알고리즘을 구현하시오.
주어진 그래프는 유향 그래프이며, 각 간선은 가중치를 가집니다.
정점은 0부터 N-1까지의 정수로 표현되며, 두 정점 간의 간선이 있을 경우 그 가중치를 알고 있습니다.

입력 형식:

  • 첫째 줄에 정점의 개수 N (1 ≤ N ≤ 1000)이 주어진다.
  • 둘째 줄에 간선의 개수 M (1 ≤ M ≤ 10000)이 주어진다.
  • 셋째 줄부터 M개의 줄에 걸쳐 각 간선의 정보가 주어진다.
    이는 “A B C”의 형태로, A에서 B로 가는 가중치 C인 간선이 있다는 의미이다.
    (1 ≤ A, B ≤ N, 1 ≤ C ≤ 1000)
  • 마지막 줄에 시작점 S (1 ≤ S ≤ N)과 도착점 E가 주어진다.

문제 풀이 과정

다익스트라 알고리즘은 그래프에서 한 정점에서 다른 정점까지의 최단 경로를 찾는 알고리즘입니다.
이 알고리즘은 음의 가중치가 없는 경우에만 올바르게 작동하므로, 가중치가 0보다 크거나 같은지 확인하는 것이 중요합니다.

아래는 코틀린을 이용한 다익스트라 알고리즘의 구현 과정입니다.

1. 그래프 표현

그래프를 표현하기 위해 인접 리스트를 사용합니다.
각 정점에 대해 그 정점에서 도달할 수 있는 정점과 그 간선의 가중치를 저장합니다.
예를 들어, 정수 배열을 이용하여 각 정점을 리스트로 표현할 수 있습니다.


    val graph = Array(N) { mutableListOf>() }
    

2. 입력 처리

입력 받은 간선 정보를 그래프에 추가합니다.
입력 형식에 따라서 반복문을 통해 각 간선의 정보를 저장합니다.


    for (i in 0 until M) {
        val (A, B, C) = readLine()!!.split(" ").map { it.toInt() }
        graph[A-1].add(Pair(B-1, C)) // A에서 B로 가는 C 가중치
    }
    

3. 다익스트라 알고리즘 구현

우선순위 큐를 이용하여 현재 최소 경로를 찾기 위한 알고리즘을 구현합니다.
다음은 다익스트라 알고리즘의 핵심 로직입니다.


    fun dijkstra(start: Int) {
        val distance = Array(N) { Int.MAX_VALUE }
        distance[start] = 0
        
        val pq = PriorityQueue>(compareBy { it.second })
        pq.add(Pair(start, 0))

        while (pq.isNotEmpty()) {
            val (current, dist) = pq.poll()

            if (dist > distance[current]) continue

            for (next in graph[current]) {
                val (nextNode, weight) = next
                val newDist = dist + weight

                if (newDist < distance[nextNode]) {
                    distance[nextNode] = newDist
                    pq.add(Pair(nextNode, newDist))
                }
            }
        }
    }
    

4. 결과 출력

최종적으로 도착점까지의 최단 거리를 계산하여 출력합니다.
도착점이 도달 불가능한 정점이라면, -1을 출력합니다.


    dijkstra(S - 1)
    val result = if (distance[E - 1] == Int.MAX_VALUE) -1 else distance[E - 1]
    println(result)
    

코드 전체

위의 로직을 바탕으로 하나의 완전한 코드는 아래와 같습니다.


    import java.util.*

    fun main() {
        val (N, M) = readLine()!!.split(" ").map { it.toInt() }
        val graph = Array(N) { mutableListOf>() }

        for (i in 0 until M) {
            val (A, B, C) = readLine()!!.split(" ").map { it.toInt() }
            graph[A - 1].add(Pair(B - 1, C))
        }

        val (S, E) = readLine()!!.split(" ").map { it.toInt() }

        fun dijkstra(start: Int) {
            val distance = Array(N) { Int.MAX_VALUE }
            distance[start] = 0

            val pq = PriorityQueue>(compareBy { it.second })
            pq.add(Pair(start, 0))

            while (pq.isNotEmpty()) {
                val (current, dist) = pq.poll()

                if (dist > distance[current]) continue

                for (next in graph[current]) {
                    val (nextNode, weight) = next
                    val newDist = dist + weight

                    if (newDist < distance[nextNode]) {
                        distance[nextNode] = newDist
                        pq.add(Pair(nextNode, newDist))
                    }
                }
            }
            return distance
        }

        dijkstra(S - 1)
        val result = if (distance[E - 1] == Int.MAX_VALUE) -1 else distance[E - 1]
        println(result)
    }
    

결론

다익스트라 알고리즘은 다양한 문제에 적용할 수 있는 강력한 도구입니다.
코틀린으로 구현하는 과정에서 그래프의 구조를 이해하고, 알고리즘의 성능을 끌어올리기 위한 여러 가지 기법을 배울 수 있었습니다.

복잡한 문제를 단순하게 푸는 접근 방법을 익히고, 이를 코드로 구현하는 연습이 필요합니다.
또한 다익스트라 알고리즘을 활용하여 현실 세계의 다양한 최단 경로 문제를 해결하는 능력을 키워보시기 바랍니다.