백준 1005 ACM Craft java

Dec 6, 2025
백준 1005 ACM Craft java

1. 문제에 대하여 📦

ACM 크래프트란 게임을 하는데, 게임에서 짓는 건물마다 순서가 존재한다.
각 건물을 짓는데는 일정 시간이 필요하다.
백준이가 짓고자 하는 건물을 짓기 위해서는 최소 얼마의 시간이 필요한지 구하라.

(1) 조건 분석 📊

건물마다 짓는데 걸리는 delay시간 및 짓기 위해 선행되어 지어져야 하는 건물이 따로 존재한다. -> 위상 정렬 문제임을 알 수 있다. 다만 '선행 건물 중 가장 느린 건축 시간을 구해서 자신의 건축 시간과 더해가야 한다.' 이 점에서 매 위상 정렬 계산마다 최장 delay 시간을 구해야 함을 알 수 있다.

2. 코드가 나오기까지 🛠️

KEY WORD: 위상정렬
  1. 비순환 그래프 세팅
  1. 위상 정렬을 하며 다음을 구한다.
    1. 진입차수를 하나 지울 때마다, 해당 빌드트리에서 걸렸던 최대 누적 시간을 현재까지 구한 최대 누적 시간과 비교하여 더 느린 걸로 갱신한다.
  1. w번 건물의 누적 건축 시간을 출력한다.
image.png

(1) 시간복잡도 분석 ⏳

전체 로직은 BFS와 같으므로, 시간복잡도는 $O(V+E)$ 이다.

3. 코드 🌐

import java.util.*; import java.io.*; public class Main { static int T, V, E, W; static class Building { int idx; int build_time; public Building(int idx, int build_time){ this.idx = idx; this.build_time = build_time; } @Override public String toString(){ return String.format("(%d %d)", idx, build_time); } } static ArrayList<ArrayList<Building>> list = new ArrayList<>(); static int [] degrees; static int [] delays; static int [] acc_times; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); T = Integer.parseInt(br.readLine()); for(int i = 0; i < T; i++){ StringTokenizer st = new StringTokenizer(br.readLine()); V = Integer.parseInt(st.nextToken()); E = Integer.parseInt(st.nextToken()); list.clear(); for(int j = 0; j <= V; j++){ list.add(new ArrayList<>()); } delays = new int [V+1]; degrees = new int [V+1]; acc_times = new int [V+1]; st = new StringTokenizer(br.readLine()); for(int j = 1 ; j<=V; j++){ delays[j] = Integer.parseInt(st.nextToken()); acc_times[j] = delays[j]; } for(int j = 0; j < E; j++){ st = new StringTokenizer(br.readLine()); int start = Integer.parseInt(st.nextToken()); int end = Integer.parseInt(st.nextToken()); list.get(start).add(new Building(end, delays[end])); degrees[end]++; } W = Integer.parseInt(br.readLine()); System.out.println(topological_sort(W)); } } public static int topological_sort(int w){ ArrayDeque<Building> aq = new ArrayDeque<>(); // 빌딩 번호 - 해당 빌딩까지 짓는 시간 포함해서 누적 시간 // 출발점 찾기 for(int i = 1; i <= V; i++){ if(degrees[i] == 0) aq.add(new Building(i, delays[i])); } while (!aq.isEmpty()){ Building now = aq.poll(); for(int i = 0; i < list.get(now.idx).size(); i++){ Building next = list.get(now.idx).get(i); degrees[next.idx]--; acc_times[next.idx] = Math.max(acc_times[next.idx], now.build_time + next.build_time); if(degrees[next.idx] == 0){ if(next.idx == w) return acc_times[next.idx]; aq.add(new Building(next.idx, acc_times[next.idx])); } } } return acc_times[w]; } }

4. 트러블 슈팅 or 배운 점📝

(1) 제일 느린 건조시간을 찾기 위해 우선순위 큐 활용은 가능한가?

불가능하다.
그래프에서 각 깊이별 도달 시기가 전부 다르기 때문에, 건조시간이 가장 빠른 게 마지막으로 목적지에 진입 할 수 도 있다.
image.png
빌딩 건조 시간이 빠른 순으로 집어넣으면, 위의 조건에서 누적 시간이 가장 느린 것이 먼저 도착해버리게 된다.