백준 1776 문제집 - Java
https://www.acmicpc.net/problem/1766
* 예제입력
4 2
4 2
3 1
* 예제출력
3 1 4 2
풀이
이 문제는 n가지 문제 중 특정 문제를 먼저 풀어야 한다.
또한 가능하면 쉬운문제(낮은 번호의 문제)부터 풀어야 한다.
이렇게 순서가 정해져 있는 작업의 문제는 위상 정렬 (Topological Sorting)
알고리즘으로 풀 수 있다. 위상 정렬 알고리즘의 조건은 비순환 방향 그래프여야 한다.
위상 정렬의 구현을 위해서 일반적으로 큐, 배열 , 인접리스트가 필요하다.
이제 순서대로 문제를 풀기 위해 단계별로 설명한다. 또한 이 문제는
가능한 쉬운 문제, 즉 번호가 낮은 문제부터 풀어야하므로 일반큐 말고 우선순위 큐를 이용할 것이다.
준비단계
문제 우선순위에 따라 인접리스트에 저장한다.
ex) 2번 문제는 4번 문제보다 먼저 풀어야 한다.
graph.get(2).add(4);
또한 그렇다면 4번 문제 입장에서는 앞에 2번이 먼저 풀어야 4번을 풀 수 있기 때문에
배열 degree에 해당 인덱스를 증가 시킨다.
detree[i] == 0 이면 i번 문제를 풀기위해 앞서 풀어야 할 문제가 없다는 뜻이다. 즉 바로 풀 수 있다
degree[4]++;
정렬단계
인접리스트 배열 degree값 세팅을 다 해줬다면 이제
본격적으로 문제를 풀기위한 위상정렬 알고리즘을 사용할 수 있다.
4 2
4 2
3 1
위 예제입력 대로라면 인접리스트 배열값은 이렇게 되어있다
인접리스트 graph
4 : 2 (4번은 2번보다 먼저 풀어야 함)
3 : 1 (3번은 1번보다 먼저 풀어야 함)
int[] degree
(1~4번 문제)
1 | 1 | 0 | 0 |
자 이제 degree에서 값이 0인 것들을 우선순위 큐에 넣어준다.
pQ = [ 3 , 4 ]
큐에서 poll() 해 3번 문제를 먼저 풀어준다.
pQ = [ 4 ]
정답 = [ 3 ]
인 상황이고 3번을 풀어줬기 때문에 인접리스트 에서 3번과 연결된 1번을 감소시켜준다.
degree[1]--;
여기서 감소시킨 값이 0이 되면 큐에 넣어준다.(중요)
0 | 1 | 0 | 0 |
pQ = [ 4, 1 ]
큐에서 poll() 해 1번 문제를 푼다. 인접리스트 에서 1번으로 시작하는 것은 없기에 넘어간다.
pQ = [ 4 ]
정답 = [ 3 , 1 ]
큐에서 poll() 해 4번 문제를 푼다.
pQ = [ ]
정답 = [ 3 , 1 , 4 ]
또한 graph에서 4번과 연결된 2번 deree감소시킨다. degree[2]--
0 | 0 | 0 | 0 |
감소시킨 degree[2]의 값이 0이 되었으므로 최종적으로 정답은
정답 = [ 3 , 1 , 4 , 2 ] 가 된다.
전체코드
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //문제 수
int m = sc.nextInt(); // 우선순위 문제 수
StringBuilder sb = new StringBuilder();
ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
for(int i=0; i<n; i++){
graph.add( new ArrayList<>() );
}
int[] degree = new int[n];
for(int i=0; i<m; i++){
//a가 b보다 먼저
int a = sc.nextInt();
int b = sc.nextInt();
graph.get(a-1).add(b-1);
degree[b-1]++;
}
//System.out.println(Arrays.toString(indegree));
PriorityQueue<Integer> pq = new PriorityQueue<>();
for(int i=0; i<n; i++){
if(degree[i]==0){
pq.offer(i);
}
}
// 큐가 빌 떄까지
while (!pq.isEmpty()){
int pre = pq.poll();
sb.append(pre+1).append(" ");
//인접리스트 탐색
for(int x : graph.get(pre)){
// 감소시킨 값이 0이면 바로 풀 수 있는 상태이기 때문에 큐에 넣어준다.
degree[x]--;
if(degree[x] == 0) pq.offer(x);
}
}
// 정답 출력
System.out.println(sb);
}
}