[이코테] 그래프 이론 - 커리큘럼 - JAVA

최영환·2022년 11월 16일
0

이코테

목록 보기
24/24
post-thumbnail

💡 문제

철수는 온라인으로 컴퓨터공학강의를 듣고 있다.

이때 각 온라인강의는 선수강의가 있을 수 있는데, 선수 강의가 있는 강의는 선수 강의를 먼저. 들어야만 해당강의를 들을 수 있다.

예를들어 '알고리즘’ 강의의 선수 강의로 '자료구조'가 존재한다면, ‘자료구조를 들은 이후에 ‘알고리즘' 강의를 들을 수 있다.

철수는 총 N개의 강의를 듣고자 한다. 모든 강의는 1번부터 N번까지의 번호를 가진다.

또한 동시에 여러 개의 강의를 들을 수 있다고 가정한다.

예를 들어 N=3일 때, 3번강의의 선수 강의로 1번과 2번강의가 있고, 1번과 2번강의는 선수강의가 없다고 가정하자.

그리고 각 강의에 대하여 강의 시간이 다음과 같다고 가정하자.

1번 강의: 30시간
2번 강의: 20시간
3번 강의: 40시간

이 경우 1번 강의를 수강하기까지의 최소 시간은 30시간, 2번 강의를 수강하기까지의 최소 시간은 20시간, 3번 강의를 수강하기까지의 최소 시간은 70시간이다.

철수가 듣고자 하는 N개의 강의 정보가 주어졌을 때, N개의 강의에 대하여 수강하기까지 걸리는 최소 시간을 각각 출력하는 프로그램을 작성하시오.

입력

  • 첫째줄에 철수가 듣고자 하는 강의의 수 N(1≤N≤500)이 주어진다.
  • 다음 N개의 줄에는 각 강의의 강의 시간과 그 강의를 듣기 위해 먼저 들어야하는 강의들의 번호가 자연수로 주어지며, 각 자연수는 공백으로 구분한다. 이때 강의시간은 100,000이하의 자연수이다.
  • 각 강의번호는 1부터 N까지로 구성되며. 각줄은 -1로 끝난다.

출력

  • N개의 강의에 대하여 수강하기까지 걸리는 최소 시간을 한 줄에 하나씩 출력한다

💬 입출력 예시

입력

5
10 -1
10 1 -1
4 1 -1
4 3 1 -1
3 3 -1

출력

10
20
14
18
17

📌 풀이(소스코드)

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Graph_03 {
    public static int n;
    public static int[] indegree = new int[501];
    public static ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>();
    public static int[] times = new int[501];

    // 위상 정렬 메소드
    public static void topologySort() {
        int[] result = new int[501];
        for (int i = 0; i <= n; i++) {
            result[i] = times[i];
        }

        Queue<Integer> q = new LinkedList<>();

        // 처음 시작할 때는 진입차수가 0인 노드를 큐에 삽입
        for (int i = 1; i <= n; i++) {
            if (indegree[i] == 0) {
                if (indegree[i] == 0) {
                    q.offer(i);
                }
            }
        }

        // 큐가 빌 때까지 반복
        while (!q.isEmpty()) {
            // 큐에서 원소 꺼내기
            int now = q.poll();
            // 해당 원소와 연결된 노드들의 진입차수에서 1 빼기
            for (int i = 0; i < graph.get(now).size(); i++) {
                result[graph.get(now).get(i)] = Math.max(result[graph.get(now).get(i)],
                        result[now] + times[graph.get(now).get(i)]);
                indegree[graph.get(now).get(i)]--;
                // 새롭게 진입차수가 0이 되는 노드를 큐에 삽입
                if (indegree[graph.get(now).get(i)] == 0) {
                    q.offer(graph.get(now).get(i));
                }
            }
        }

        // 위상 정렬을 수행한 결과 출력
        for (int i = 1; i <= n; i++) {
            System.out.println(result[i]);
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        n = sc.nextInt();

        // 그래프 초기화
        for (int i = 0; i <= n; i++) {
            graph.add(new ArrayList<Integer>());
        }

        // 방향 그래프의 모든 간선 정보를 입력 받기
        for (int i = 1; i <= n; i++) {
            int x = sc.nextInt();
            times[i] = x;
            // 선수 강의 입력
            while (true) {
                x = sc.nextInt();
                if (x == -1)
                    break;
                indegree[i]++;
                graph.get(x).add(i);
            }
        }

        topologySort();
        sc.close();
    }
}

📄 해설

  • 위상 정렬(Topology Sort) 응용문제
  • 각 노드에 대하여 인접 노드를 확인할 때, 인접 노드에 대하여 현재보다 강의 시간이 더 긴 경우를 찾는다면, 더 오랜 시간이 걸리는 경우의 시간 값을 저장하는 방식으로 결과 테이블을 갱신하여 답을 구할 수 있음
    => 위상 정렬을 수행하면서 매번 간선 정보를 확인하여 결과 테이블 갱신
profile
조금 느릴게요~

0개의 댓글