DP + 위상 정렬
번째 건물이 완성되기까지 걸리는 최소 시간
번째 건물을 짓기 전에 지어야 하는 건물 수
번째 건물을 짓는데 걸리는 시간
번째 건물이 먼저 지어져야 하는 건물들의 리스트
는 를 짓기 위해서 먼저 지어야하는 건물의 번호
값이 인 를 큐에 넣고 다음 단계를 반복해 테이블을 채움
큐에서 를 꺼내고 에 를 더함
에서 다음 건물 에 대해 값을 1 뺌
가 보다 작다면
가 0이 되었으면 큐에 삽입
모든 에 대해 를 출력하면 정답
건물이 완성되기까지 걸리는 최소 시간은 먼저 지어져야 하는 건물들이 완성되기까지 걸리는 최소 시간에 건물을 짓는데 걸리는 시간을 더하면 된다.
따라서 를 번째 건물이 완성되기까지 걸리는 최소 시간으로 정의할 수 있고
는 를 짓기 위해서 먼저 지어야하는 건물의 번호
와 같은 점화식이 나오게 된다.
값이 이 되었다는 뜻은 번째 건물을 짓기 전에 먼저 지어야하는 건물을 모두 지었다는 뜻으로 값이 0이 되었을 때 큐에 집어넣어 값을 계산한다.
이때 번째 건물을 지은 후에 지어야 하는 건물을 라고 하면 의 값과 의 값을 비교하고 더 큰 값을 저장해 를 짓기 위해 지어야 하는 건물들의 완성 시간을 비교해서 를 짓기 위해 지어야 하는 모든 건물들이 완성되는 시간을 구할 수 있다.
그 후에 를 짓기 위해 지어야 하는 건물 를 짓는데 완료했기 때문에 의 값을 1 줄여준다. 이때 의 값이 0이 되면 를 짓기 위해 지어야 하는 모든 건물들이 지어졌다는 뜻이므로 를 큐에 넣는다.
이렇게 모든 건물에 대해 테이블을 구하고 출력하면 정답이다.
import java.util.StringTokenizer
fun main(){
val br = System.`in`.bufferedReader()
val N = br.readLine().toInt()
val dp = IntArray(N + 1){0}
val times = IntArray(N + 1){0}
val prev = IntArray(N + 1){0}
val next = Array(N + 1){ArrayList<Int>()}
for(i in 1..N){
val st = StringTokenizer(br.readLine())
times[i] = st.nextToken().toInt()
var j = st.nextToken().toInt()
while(j != -1){
prev[i]++
next[j].add(i)
j = st.nextToken().toInt()
}
}
val queue = ArrayDeque<Int>()
for(i in 1..N){
if(prev[i] == 0){
queue.add(i)
}
}
while(queue.isNotEmpty()){
val i = queue.removeFirst()
dp[i] += times[i]
for(j in next[i]){
prev[j]--
if(dp[j] < dp[i]){
dp[j] = dp[i]
}
if(prev[j] == 0){
queue.add(j)
}
}
}
for(i in 1..N){
println(dp[i])
}
}