안녕하세요! 오늘은 자바를 이용한 코딩 테스트에서 자주 등장하는 위상 정렬에 대해 알아보겠습니다. 위상 정렬은 Directed Acyclic Graph(DAG)에서 사용되는 알고리즘으로, 여러 개의 작업을 수행할 때 작업 간의 선후 관계를 고려하여 작업 순서를 결정하는데 매우 유용합니다.
1. 위상 정렬이란?
위상 정렬은 방향 그래프에서의 정점 순서를 나열하여 각 정점의 모든 선행 정점이 나열된 이후에 나오는 순서를 말합니다. 일반적으로 위상 정렬은 다음과 같은 경우에 사용됩니다:
- 프로젝트 작업 중, 작업의 순서를 결정할 때 (예: 작업 A가 끝나야 작업 B를 시작할 수 있는 경우)
- 학습 과정에서 수업의 순서를 결정할 때 (예: 선행 과목이 있어야 수강할 수 있는 경우)
2. 문제 설명
다음과 같은 문제를 해결해 보겠습니다:
3. 위상 정렬 알고리즘
위상 정렬을 수행하기 위해서는 ‘진입 차수’를 활용하는 방법과 ‘DFS’ 기반의 방법 두 가지가 있습니다. 여기서는 진입 차수 기반의 위상 정렬 방법을 설명하겠습니다.
3.1. 진입 차수 기반 위상 정렬
진입 차수 기반의 위상 정렬은 다음과 같은 단계로 이루어집니다:
- 그래프의 모든 정점의 진입 차수를 계산합니다.
- 진입 차수가 0인 정점을 큐에 넣습니다.
- 큐에서 정점을 하나씩 꺼내고, 해당 정점과 연결된 모든 정점의 진입 차수를 1 감소시킵니다.
- 진입 차수가 0이 된 정점은 큐에 추가합니다.
- 위 단계를 큐가 비어있지 않을 때까지 반복합니다.
4. 자바 코드 구현
위상 정렬 알고리즘을 Java로 구현해 보겠습니다. 아래는 문제 해결을 위한 Java 코드입니다.
import java.util.*;
public class TopologicalSort {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt(); // 수업의 개수
int M = scanner.nextInt(); // 관계의 개수
List> graph = new ArrayList<>();
int[] inDegree = new int[N + 1];
for (int i = 0; i <= N; i++) {
graph.add(new ArrayList<>());
}
// 그래프 입력 처리
for (int i = 0; i < M; i++) {
int A = scanner.nextInt();
int B = scanner.nextInt();
graph.get(A).add(B);
inDegree[B]++;
}
// 진입 차수가 0인 노드를 큐에 담기
Queue queue = new LinkedList<>();
for (int i = 1; i <= N; i++) {
if (inDegree[i] == 0) {
queue.add(i);
}
}
List result = new ArrayList<>();
while (!queue.isEmpty()) {
int current = queue.poll();
result.add(current);
for (int next : graph.get(current)) {
inDegree[next]--; // 진입 차수 감소
if (inDegree[next] == 0) {
queue.add(next);
}
}
}
// 순서가 결정되었는지 확인
if (result.size() == N) {
for (int i : result) {
System.out.print(i + " ");
}
} else {
System.out.println(0);
}
scanner.close();
}
}
5. 코드 설명
위의 Java 코드는 다음과 같은 방식으로 동작합니다:
- 입력을 받기 위해 Scanner를 사용하며, 수업의 개수 N과 관계의 개수 M을 읽습니다.
- 그래프와 진입 차수를 저장할 배열을 초기화합니다. 각 수업에 대한 그래프 정보를 리스트 형태로 저장합니다.
- M개의 관계를 입력 받으며, 각 수업 간의 관계를 그래프에 추가하고 진입 차수를 업데이트 합니다.
- 진입 차수가 0인 노드를 큐에 추가하여 시작합니다.
- 큐에서 정점을 꺼내고, 해당 정점과 연결된 모든 다른 정점의 진입 차수를 1 감소시킵니다.
- 만약 이 과정에서 진입 차수가 0이 되는 정점이 있다면 큐에 추가합니다.
- 예외 상황을 처리하며, 최종적으로 가능한 순서대로 수업을 출력합니다.
6. 예제 테스트
아래와 같은 입력을 테스트해 보겠습니다:
5 4
1 2
1 3
2 4
3 4
이 예제는 5개의 수업과 4개의 관계를 항상 포함하기 때문에 적절히 수행할 수 있습니다. 올바른 출력은 수업을 들을 수 있는 가능한 순서입니다.
7. 시간 복잡도
위상 정렬의 시간 복잡도는 O(V + E)입니다. 여기서 V는 정점의 수(N)이고 E는 간선의 수(M)이므로 대규모 그래프에서도 효율적으로 작동합니다.
8. 결론
오늘은 자바를 이용한 위상 정렬 알고리즘에 대해 알아보았습니다. 이 알고리즘은 다양한 분야에서 유용하게 활용될 수 있으며, 코딩 테스트에서도 자주 등장하니 꼭 연습하시기 바랍니다. 복잡한 문제를 해결하는데 있어 위상 정렬이 큰 도움이 될 것입니다!