// [백준] 1916. 최소비용 구하기 (Kotlin)
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.*
lateinit var dist: Array<Int>
lateinit var map: Array<ArrayList<Node>>
data class Node(val des: Int, val value: Int) : Comparable<Node> {
override fun compareTo(other: Node): Int = value - other.value
}
fun main() = with(BufferedReader(InputStreamReader(System.`in`))){
val n = readLine().toInt()
val m = readLine().toInt()
dist = Array(n + 1){Int.MAX_VALUE}
map = Array(n + 1) {arrayListOf()}
// 그래프 생성
for(i in 0 until m){
val st = StringTokenizer(readLine())
val start = st.nextToken().toInt()
val des = st.nextToken().toInt()
val value = st.nextToken().toInt()
map[start].add(Node(des,value)) // start에서 des로 가는 가중치 value
}
val st = StringTokenizer(readLine())
val start = st.nextToken().toInt()
val des = st.nextToken().toInt()
dijkstra(start) // 시작점에서부터 탐색 시작
println(dist[des]) // 목적지 최솟값 출력
}
fun dijkstra(srt: Int){
val queue = PriorityQueue<Node>()
dist[srt] = 0 // 시작점 자신은 0
queue.add(Node(srt,0)) // 시작점 넣기
while(queue.isNotEmpty()){
val curIndex = queue.peek().des // 현재 노드 인덱스
val curValue = queue.peek().value // 현재 노드까지의 거리
queue.poll()
if (dist[curIndex] < curValue) continue // 가중치가 더 큰 경로 탐색 X
// 인접리스트 탐색
for (i in map[curIndex]) {
val nextDes = i.des
val nextValue = curValue + i.value
// 최솟값 갱신
if (nextValue < dist[nextDes]) {
dist[nextDes] = nextValue
queue.add(Node(nextDes, nextValue))
}
}
}
}
벨만-포드 알고리즘
모든 간선을 탐색하여 최단거리 테이블 갱신
1번 과정을 (정점의 수 - 1) 만큼 반복
1번 과정을 한번 더 수행했을 때 최단거리 테이블이 갱신될 경우 싸이클 발생 확인
정점의 수를 n이라 할 때, 사이클이 존재하지 않는다면 최단 거리는 n-1 이다.
벨만-포드 알고리즘은 위 성질을 활용하여, 사이클이 발생하는지 찾는다.
사이클이 없을 때, 모든 간선을 n-1 만큼 반복 탐색하면 모든 최단거리 테이블이 완성된다.
그 후 한번 더 탐색했을 때 최단거리 테이블이 갱신된다면, 음수의 사이클이 존재하는 것이다.
// [백준] 11657. 타임머신 (Kotlin)
import java.io.BufferedReader
import java.io.InputStreamReader
import java.util.*
lateinit var dist: Array<Long>
lateinit var adj: ArrayList<Node>
var n = 0
var m = 0
var cycle = false
data class Node(val start: Int, val des: Int, val value: Long)
fun main() = with(BufferedReader(InputStreamReader(System.`in`))){
val st = StringTokenizer(readLine())
n = st.nextToken().toInt()
m = st.nextToken().toInt()
dist = Array(n + 1){Long.MAX_VALUE} // 최솟값 저장
adj = arrayListOf() // 간선 정보 저장
// 간선 정보 입력
for(i in 0 until m){
val st = StringTokenizer(readLine())
val start = st.nextToken().toInt()
val des = st.nextToken().toInt()
val value = st.nextToken().toLong()
adj.add(Node(start,des,value))
}
bellmanFord(1)
// 사이클이 존재하면
if (cycle){
println("-1")
}
// 사이클이 존재하지 않으면
else{
for(i in 2 .. n){
// 경로가 없다면
if(dist[i] == Long.MAX_VALUE) {
dist[i] = -1
}
println(dist[i])
}
}
}
fun bellmanFord(srt: Int){
dist[srt] = 0 // 시작점 자신은 0
for(i in 1 .. n){
for(cur in adj){
val curStart = cur.start
val curDes = cur.des
val nextValue = dist[curStart] + cur.value
// 현재값이 초기화 된 상태이고 최솟값을 갱신할 수 있으면
if(dist[curStart] != Long.MAX_VALUE && dist[curDes] > nextValue){
dist[curDes] = nextValue
// n번째 반복 때 최솟값이 갱신되었다면
if(i == n){
cycle = true
}
}
}
}
}