ALGORITHM/BOJ

[백준] 2252 줄 세우기

0298 2021. 1. 12. 22:13

www.acmicpc.net/problem/2252

 

2252번: 줄 세우기

첫째 줄에 N(1≤N≤32,000), M(1≤M≤100,000)이 주어진다. M은 키를 비교한 회수이다. 다음 M개의 줄에는 키를 비교한 두 학생의 번호 A, B가 주어진다. 이는 학생 A가 학생 B의 앞에 서야 한다는 의미이

www.acmicpc.net

2021-01-12


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.StringTokenizer;
 
public class Main2252 {
    public static int N, M, arr[];
    public static List<List<Integer>> list;
    public static Queue<Integer> q;
    
    public static void main(String[] args) throws Exception{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(bf.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        
        arr = new int[N+1];
        list = new ArrayList<>();
        q = new LinkedList<>();
        
        for(int i = 1; i <= N+1; i++) list.add(new ArrayList<>());
    
        for(int i = 0; i < M; i++) {
            st = new StringTokenizer(bf.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            list.get(x).add(y); // x -> y
            arr[y]++// count 진입 차수
        }
        
        for(int i = 1; i <= N; i++) { // 진입 차수가 0이면 queue에 넣는다 
            if(arr[i] == 0) { // 진입 차수가 0이라는 의미이다.
                q.add(i);
            }
        }
        
        StringBuilder sb = new StringBuilder();
        
        for(int i = 1; i <= N; i++) { // 학생 수를 다 돌아본다.
            if(q.isEmpty()) { // 사이클이 발생하는 경우
                break;
            }
            
            int zero = q.poll();
            sb.append(zero + " "); // 큐에서 제거 후 순서에 저장 
            
            for(int k = 0; k < list.get(zero).size(); k++) {   
                int num = list.get(zero).get(k); // 연결된 정점들 중에서
                if(--arr[num] == 0) { // 간선을 제거하고 진입차수가 0이된 정점을 
                    q.add(num); // 큐에 넣어준다.
                }
            }
        }
        
        System.out.println(sb.toString());
    }
}
 
cs

#문제풀이

위상정렬(Topological Sort)를 이용하여 푼 문제이다. 

 

1. 선수 조건이 주어진 입력을 받을 때, 각각의 학생에 대해서 진입 차수가 있는지에 대해서도 같이 체크한다. 

 

2. 맨 처음 모든 정점을 돌면서 진입 차수가 0인 것들은 queue에 넣는다.

 

3. 정점의 개수만큼 돌면서, queue에서 하나씩 제거하면서 순서에 저장을 한다.

 

4. 제거한 그 정점과 연결된 간선들을 찾아 제거 하면서, 동시에 새롭게 진입 차수가 0이 된 정점들을 체크해서 queue에 넣는다.

 

5. 3~4를 반복한다.