PS(Problem Solving)/BOJ

[백준/BOJ] 1005번: ACM Craft

JunsuKim 2022. 9. 13.

목차

728x90

문제

https://www.acmicpc.net/problem/1005

 

1005번: ACM Craft

첫째 줄에는 테스트케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 주어진다. 첫째 줄에 건물의 개수 N과 건물간의 건설순서 규칙의 총 개수 K이 주어진다. (건물의 번호는 1번부...

www.acmicpc.net

해설

선행 순서가 정해져 있고, 이를 특정 건물을 짓기까지 얼마나 오랜 시간이 걸릴지 구해야 한다.

선행 순서가 있는 문제에서 전체적인 순서를 구할 때 위상 정렬을 사용한다.

문제의 예제 2번을 보며 풀이를 해보자.

[백준/BOJ] 1005번: ACM Craft - undefined - 해설

우선 차수가 0인 1번 정점부터 시작을 한다.

위상 정렬을 진행하므로 1번 정점을 큐에 넣고, 이와 연결된 간선들을 모두 제거한다.

[백준/BOJ] 1005번: ACM Craft - undefined - 해설

이제 차수가 0인 것은 2번과 3번이다.

우리는 7번 건물을 짓는 것이 목표이므로 2번과 3번 건물을 모두 지어야만 한다.

이 중 더 오래 걸리는 시간을 더해주면 된다.

위 표에서 소요 시간을 result 배열로 선언했는데, result[다음 건물]  = max(result[다음 건물], result[현재 건물] + runningtime(시간)[다음 건물])을 비교해준다.

즉, result[2] = max(20, 20 + 10)이므로 result[2] = 30이 된다.

또한 result[3] = max(10, 10 +1)로 result[3] = 11이다.

 

이 과정을 계속 반복해보자.

이제 2와 3이 큐에 들어가고 이와 연결된 간선들을 모두 제거한다.

[백준/BOJ] 1005번: ACM Craft - undefined - 해설

중간 과정이 많이 생략되었지만 설명을 해보자면,

우선 2와 3이 큐에 있고, 2가 먼저 pop이 된다.

이때, 2와 연결되있던 간선은 4와 5가 있고, 즉 result[4] = max(5, 30 + 5), result[5] = max(8, 30 + 8)이 된다.

또한 3과 연결되있던 6은 result[6] = max(11, 11 + 7)이 된다.

[백준/BOJ] 1005번: ACM Craft - undefined - 해설

7은 5, 6과 모두 연결되있었다.

따라서 result[7] = max(35, 35 + 1)을 한 후, result[7] = max(36, 38 + 1)이 된다.

따라서 result[7] = 39이다.

 

우리는 7번 건물을 가장 빨리 짓는 시간을 알아내면 된다. 따라서 수행을 끝내고, result[7]을 출력해주면 된다.

코드

import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.max

private lateinit var graph: ArrayList<ArrayList<Int>>
private lateinit var degree: IntArray
private lateinit var runningTime: IntArray

fun main() = with(System.`in`.bufferedReader()) {
    val testCase = readLine().toInt()
    repeat(testCase) {
        val (buildingCnt, ruleCnt) = readLine().split(" ").map { it.toInt() }

        graph = ArrayList(ArrayList())
        repeat(buildingCnt + 1) { graph.add(ArrayList()) }

        degree = IntArray(buildingCnt + 1)
        runningTime = IntArray(buildingCnt + 1)

        val st = StringTokenizer(readLine())
        for(i in 1 .. buildingCnt) { runningTime[i] = st.nextToken().toInt() }

        repeat(ruleCnt) {
            val (first, second) = readLine().split(" ").map { it.toInt() }
            graph[first].add(second)
            degree[second]++
        }

        val targetBuilding = readLine().toInt()

        build(buildingCnt, targetBuilding)
    }
}

private fun build(n: Int, targetBuilding: Int) {
    val que: Queue<Int> = LinkedList()
    val result = IntArray(n + 1)

    for(i in 1 .. n) {
        result[i] = runningTime[i]

        if(degree[i] == 0) que.add(i)
    }

    while(que.isNotEmpty()) {
        val cur = que.poll()

        for(i in graph[cur]) {
            result[i] = max(result[i], result[cur] + runningTime[i])
            degree[i]--

            if(degree[i] == 0) que.add(i)
        }
    }

    println(result[targetBuilding])
}
728x90

댓글