문제
시작지점 S에서 출발하여 2명의 사람이 각각 A지점과 B지점에 가야할 때 최단거리를 구하는 문제이다.
풀이
시작지점에서 출발하여 A, B를 돌도록 최단거리를 구하면 안된다.
그 이유는 한 지점에서 각각의 사람이 갈라져서 이동하기 때문이다.
예를들어 위의 사진의 경우 S에서 출발하여 1번노드로 이동후 B는 5 -> 3 -> 2 노드로 이동하고 A는 5 -> 6 노드로 이동하므로
각각의 경우를 따로따로 구해야 한다.
여기서 봐야할 점은 S에서 출발하여 A, B 로 각각 간다는점인데 이를 다시생각하면 한 지점에서 S, A, B지점으로 이동한 거리를 모두 합한 값이 된다.
따라서 각 지점에 대해 S, A, B 까지의 최단거리를 합한 후 가장 작은 값을 구하면 된다.
data class Node(val end: Int, val weight: Int): Comparable<Node> {
override fun compareTo(other: Node) = weight - other.weight
}
weight값을 기준으로 정렬하는 data class Node를 정의해준다.
private lateinit var dst: IntArray
private lateinit var list: Array<ArrayList<Node>>
거리값을 저장한 dst와 간선정보를 저장할 list를 선언해준다.
var answer: Int = Int.MAX_VALUE
list = Array(n + 1) { ArrayList<Node>() }
for (i in 0 until fares.size) {
val (start, end, weight) = fares[i].map { it }
list[start].add(Node(end, weight))
list[end].add(Node(start, weight))
}
정답을 출력할 answer는 최대값으로 초기화하고
간선의 정보를 저장할 list는 n + 1의 크기로 초기화한다. 해당 배열은 Node를 가지는 ArrayList를 가진다.
따라서 [ [Node, Node], [Node], [Node, Node, Node] ] 의 형태를 가진다.
이후 해당 list에 간선의 정보를 입력받는다. 해단 간선은 양방향이기 때문에 양쪽 방향을 모두 저장한다.
fun dijkstra(start: Int, n: Int): IntArray {
val q = PriorityQueue<Node>()
val isVisited = BooleanArray(n + 1)
dst = IntArray(n + 1) { Int.MAX_VALUE }
dst[start] = 0
q.offer(Node(start, 0))
while (q.isNotEmpty()) {
val cur = q.poll()
if (isVisited[cur.end]) continue
isVisited[cur.end] = true
for (next in list[cur.end]) {
if (dst[next.end] > dst[cur.end] + next.weight) {
dst[next.end] = dst[cur.end] + next.weight
q.offer(Node(next.end, dst[next.end]))
}
}
}
return dst
}
다익스트라의 구현부이다.
다익스트라를 여러번 실행해야하기 때문에 해당 함수 내부에서 visited를 관리해주었다.
dst 값을 초기화해주고 현재 시작위치의 거리를 0으로 해준다.
그 후 priority queue인 q에 넣어주고 while문을 실행한다.
이후는 기존 다익스트라의 구현과 같다.
마지막으로 값을 할당한 dst를 return한다.
val dstS = dijkstra(s, n)
val dstA = dijkstra(a, n)
val dstB = dijkstra(b, n)
for (i in 1..n) {
if (dstS[i] == Int.MAX_VALUE || dstA[i] == Int.MAX_VALUE || dstB[i] == Int.MAX_VALUE) continue
answer = min(answer, dstS[i] + dstA[i] + dstB[i])
}
다익스트라를 사용하여 거리를 구하는 부분이다.
dstS, A, B 를 각각의 지점에서 시작하는 최단거리값을 할당해준다.
마지막으로 모든 값을 더했을 때의 최소값을 answer에 할당한다.
코드
import java.util.*
import kotlin.math.*
class Solution {
private lateinit var dst: IntArray
private lateinit var list: Array<ArrayList<Node>>
fun solution(n: Int, s: Int, a: Int, b: Int, fares: Array<IntArray>): Int {
var answer: Int = Int.MAX_VALUE
list = Array(n + 1) { ArrayList<Node>() }
for (i in 0 until fares.size) {
val (start, end, weight) = fares[i].map { it }
list[start].add(Node(end, weight))
list[end].add(Node(start, weight))
}
val dstS = dijkstra(s, n)
val dstA = dijkstra(a, n)
val dstB = dijkstra(b, n)
for (i in 1..n) {
if (dstS[i] == Int.MAX_VALUE || dstA[i] == Int.MAX_VALUE || dstB[i] == Int.MAX_VALUE) continue
answer = min(answer, dstS[i] + dstA[i] + dstB[i])
}
return answer
}
fun dijkstra(start: Int, n: Int): IntArray {
val q = PriorityQueue<Node>()
val isVisited = BooleanArray(n + 1)
dst = IntArray(n + 1) { Int.MAX_VALUE }
dst[start] = 0
q.offer(Node(start, 0))
while (q.isNotEmpty()) {
val cur = q.poll()
if (isVisited[cur.end]) continue
isVisited[cur.end] = true
for (next in list[cur.end]) {
if (dst[next.end] > dst[cur.end] + next.weight) {
dst[next.end] = dst[cur.end] + next.weight
q.offer(Node(next.end, dst[next.end]))
}
}
}
return dst
}
}
data class Node(val end: Int, val weight: Int): Comparable<Node> {
override fun compareTo(other: Node) = weight - other.weight
}
'알고리즘' 카테고리의 다른 글
[프로그래머스 kotlin] 괄호 회전하기 (0) | 2024.05.06 |
---|---|
[프로그래머스 kotlin] 타겟 넘버 (0) | 2024.05.02 |
[백준 kotlin] 1753 최단경로 (1) | 2024.04.18 |
[백준 kotlin] 1806 부분 합 (0) | 2024.04.15 |
[백준 kotlin] 1260 DFS와 BFS (1) | 2024.04.13 |