PS

[BOJ 2252] 줄 세우기 (Java)

기맹기 2022. 8. 30. 03:38

BOJ 2252 줄 세우기

난이도 : 골드 3

https://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

 

전략

문제 이름만 봤을 때는 7568 덩치 랑 비슷해보이지만, 자세히 읽어보면 그래프 문제라는 것을 알 수 있다.

 

일부 학생들에 대해서만 키 비교가 있고 이에 따라 순서가 정해지므로 방향 그래프인데

 

물리적인 키를 서로 비교한 것이기 때문에 사이클이 생길 수 없는 조건이다.

 

이는 위상 정렬로 간단하게 풀 수 있다.

 

노드 기준으로 들어오는 간선의 개수를 linked라고 했을 때

1. linked가 0인 노드들을 모두 큐에 넣는다.

2. 큐에서 노드를 제거(방문)하고 연결된 노드들의 linked를 감소시킨다.

3. linked가 0이 된 노드들을 큐에 삽입한다.

4. 2 ~ 3을 반복한다.

 

만약 N만큼의 반복이 이루어지지 않은 (모든 노드를 방문하지 않은) 상태에서 큐가 비었다면

사이클이 있는 그래프로 위상정렬을 할 수 없다.

하지만 문제 조건에 의해서 사이클이 없는 입력만 주어지므로 검사를 하지 않도록 구현하였다.

 

시간 복잡도는 O(N + M)이 된다.

 

시행착오

시행 착오는 없었다.

 

코드

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class Main {

    static int N, M;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] line = br.readLine().split(" ");
        N = Integer.parseInt(line[0]);
        M = Integer.parseInt(line[1]);
        Node[] nodes = new Node[N + 1];
        for (int i = 1; i <= N; i++)
            nodes[i] = new Node(i);

        for (int i = 0; i < M; i++) {
            line = br.readLine().split(" ");
            int first = Integer.parseInt(line[0]);
            int second = Integer.parseInt(line[1]);
            nodes[first].link.add(nodes[second]);
            nodes[second].linked++;
        }

        System.out.println(topologicalSort(nodes));
        br.close();
    }

    static StringBuilder topologicalSort(final Node[] nodes) {
        StringBuilder sb = new StringBuilder();
        Queue<Node> queue = new LinkedList<>();

        for (int i = 1; i <= N; i++) {
            if (nodes[i].linked == 0)
                queue.offer(nodes[i]);
        }

        for (int i = 0; i < N; i++) {
            Node cur = queue.poll();
            sb.append(cur.num + " ");

            for (Node next : nodes[cur.num].link) {
                if (--next.linked == 0)
                    queue.add(next);
            }
        }

        return sb;
    }

    static class Node {
        int num;
        int linked = 0;
        ArrayList<Node> link = new ArrayList<>();

        Node(int num) {
            this.num = num;
        }
    }
}

 

깨달은 점

위상 정렬을 처음 구현해봤는데, 단순하면서도 다양한 문제에서 유용하게 사용할 수 있을 것 같다.