본문 바로가기

CodingTEST

[백준 1516] 게임 개발 (JAVA)

반응형

백준 1516번 문제 - 게임 개발

 

1516번: 게임 개발

첫째 줄에 건물의 종류 수 N(1 ≤ N ≤ 500)이 주어진다. 다음 N개의 줄에는 각 건물을 짓는데 걸리는 시간과 그 건물을 짓기 위해 먼저 지어져야 하는 건물들의 번호가 주어진다. 건물의 번호는 1부

www.acmicpc.net


문제 분석

 

  • 건물을 짓기 위해 선행되어야하는 건물이 있다. 그럼 이 건물을 짓기 위해 필요한 최소 시간을 출력한다.
    • 2, 3 둘 다 1번 건물이 필요할 때 : 1번 짓고 2번 1번 또 짓고 3번이 아니라, 1번 짓고 2, 3을 짓는 것으로 시간을 잰다.

해결 키 포인트

 

  • 위상 정렬 개념 이해
  • 위상 정렬할 때, inDegree 배열에 선행되어야 할 건물 개수가 아닌 자신이 선행되어야하는 건물의 개수로 한다.
  • 현재 이미 건물이 건설되었을 경우와 아닌 경우 처리해야한다.
    • if (sum[index] == 0) sum[index] = building[index]; 
    • else sum[index] = Math.max(sum[index], building[index]);
  • 현재 체크하는 건물이 선행 건물인 경우, 해당 건물이 필요한 건물의 시간을 구하는 법
    • 선행 건물을 통해 짓는 경우와 직접 짓는 경우 중 더 오래 걸리는 시간을 선택해야한다.
    • sum[material] = Math.max(sum[material], sum[index] + building[material]);

위상 정렬

 사이클이 없는 방향 그래프에서 노드 순서를 찾는 알고리즘이다.

 

위상 정렬에서는 항상 유일한 값으로 정렬되지 않는다. 
또한 사이클이 존재하면 노드 간의 순서를 명확하게 정의할 수 없으므로 위상 정렬을 적용 할 수 없다.

 

알고리즘

 

1. 자신이 가르키는 에지(노드)들을 ArrayList로 제작해 구현한다.

1 ➡️ 2, 3

2 ➡️ 4, 5

3 ➡️ 4

4 ➡️ 5

5

 

2. 진입 차수 배열을 구현한다. 진입 차수는 자기 자신을 가리키는 에지의 개수이다.

1 : 0

2 : 1

3 : 1

4 : 2

5 : 2

 

3. 진입 차수 배열에서 진입차수가 0인 노드를 선택하고 선택된 노드를 정렬 배열에 저장한다.
0인 노드 ➡️ 1

 

4. 그 후 인접 리스트에서 선택된 노드가 가리키는 노드들의 진입 차수를 1씩 뺀다.

1 : 0

2 : 1 - 1 : 0

3 : 1 - 1 : 0

4 : 2

5 : 2

 


코드

 

import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;

public class Main {
    public static ArrayList<Integer>[] lists;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        // N 입력
        int N = Integer.parseInt(br.readLine());

        // 변수 초기화
        lists = new ArrayList[N];
        for (int i = 0; i < N; i++)
            lists[i] = new ArrayList<>();
        int[] inDegrees = new int[N];
        int[] building = new int[N];

        // N개의 건물들을 짓는데 걸리는 시간과 필요한 자원 입력
        for (int i = 0; i < N; i++) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            int time = Integer.parseInt(st.nextToken());
            building[i] = time;

            while (st.countTokens() > 1) {
                int material = Integer.parseInt(st.nextToken()) - 1;
                inDegrees[i]++;
                lists[material].add(i);
            }
        }

        int [] sum = new int[N];
        // 각 건물을 건설할 때 필요한 건설 시간 알아내기
        for (int i = 0; i < N; i++) {
            int index = getZeroDegree(inDegrees);

            // 현재 건물이 이미 건설되었을 경우에 대한 처리
            if (sum[index] == 0)
                sum[index] = building[index];
            else
                sum[index] = Math.max(sum[index], building[index]);

            ArrayList<Integer> list = lists[index];
            for(int j=0;j<list.size();j++) {
                int material = list.get(j);
                // 선행 건물을 통해 짓는 경우와 직접 짓는 경우 중 더 오래 걸리는 시간을 선택
                sum[material] = Math.max(sum[material], sum[index] + building[material]);
                inDegrees[material]--;
            }
        }

        // 각 건물을 건설할 때 필요한 건설 시간 출력
        for (int i = 0; i < N; i++) {
            bw.write(sum[i]+"\n");
        }
        bw.flush();
        bw.close();
    }

    public static int getZeroDegree(int [] inDegree) {
        int index = 0;

        for(int i=0;i<inDegree.length;i++) {
            if(inDegree[i] == 0) {
                index = i;
                break;
            }
        }
        inDegree[index]--;

        return index;
    }
}
 
반응형

'CodingTEST' 카테고리의 다른 글

[백준 7662] 이중 우선순위 큐 (JAVA)  (0) 2023.09.19
[백준 4358] 생태학 (JAVA)  (0) 2023.09.19
[백준 2252] 줄 세우기 (JAVA)  (1) 2023.08.27
[백준 1043] 거짓말 (JAVA)  (1) 2023.08.27
[백준 1976] 여행 가자 (JAVA)  (0) 2023.08.26