백준 온라인 저지/Platinum

[BOJ] 2150 - Strongly Connected Component

jooona 2021. 12. 30. 02:17
반응형

개인적인 풀이일 뿐, 최적의 정답이 아님을 알려드립니다.

 

문제

https://www.acmicpc.net/problem/2150

 

2150번: Strongly Connected Component

첫째 줄에 두 정수 V(1 ≤ V ≤ 10,000), E(1 ≤ E ≤ 100,000)가 주어진다. 이는 그래프가 V개의 정점과 E개의 간선으로 이루어져 있다는 의미이다. 다음 E개의 줄에는 간선에 대한 정보를 나타내는 두 정

www.acmicpc.net

난이도: 플래티넘 5

사용언어: JAVA

 

풀이

 

이름 그대로 Strongly Connected Component(SCC) 문제의 가장 기본적인 유형입니다. 저는 코사라주 알고리즘을 이용하여 문제를 해결하였습니다. 코사라주 알고리즘은 아래의 링크에서 더 자세하게 확인하실 수 있습니다.

 

https://jooona.tistory.com/159

 

[알고리즘] 코사라주 알고리즘

코라사주 알고리즘은 SCC(Strongly Connected Component) 문제를 해결하기 위한 알고리즘입니다. SCC란 강한 연결 관계라고 번역될 수 있습니다. 1. 강한 연결 관계? SCC는 그래프에서 노드 간의 연결 관계가

jooona.tistory.com

 

 

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import java.io.*;
import java.util.*;
 
public class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static ArrayList<ArrayList<Integer>> conn = new ArrayList<>(); // 순방향 그래프
    static ArrayList<ArrayList<Integer>> reconn = new ArrayList<>(); // 역방향 그래프
    static boolean[] visit; // 방문 여부 확인
    static int[] scc; // 어떤 노드들이 하나의 SCC로 묶였는지를 표시하기 위한 배열
    static Stack<Integer> stack = new Stack<>(); // 스택
 
    static int N, M;
 
    public static void dfs(int node) { // 순방향 그래프에 대한 dfs
        visit[node] = true// 방문했다고 체크
 
        for (int i = 0; i < conn.get(node).size(); i++) {
            int next = conn.get(node).get(i); // 다음 탐색할 노드 선정
 
            if (visit[next] == false) { // 아직 방문하지 않은 노드라면
                dfs(next); // 순방향 그래프에 대한 dfs 진행
            }
        }
        stack.push(node); // 탐색이 끝난 노드는 스택에 push
    }
 
    public static void redfs(int node, int number) { // 역방향 그래프에 대한 dfs.
                                                     // node: 현재 탐색 중인 node, number: 현재 scc 번호
        visit[node] = true// 방문했다고 체크
        scc[node] = number; // 탐색되는 노드는 현재 scc에 포함
 
        for (int i = 0; i < reconn.get(node).size(); i++) {
            int next = reconn.get(node).get(i); // 다음 탐색할 노드 선정
            if (visit[next] == false) { // 아직 방문하지 않은 노드라면
                redfs(next, number); // 역방향 그래프에 대한 dfs 진행
            }
        }
    }
 
    public static void main(String[] args) throws IOException {
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        visit = new boolean[N + 1];
        scc = new int[N + 1];
 
        for (int i = 0; i < N + 1; i++) {
            conn.add(new ArrayList<>());
            reconn.add(new ArrayList<>());
        }
 
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
 
            int n = Integer.parseInt(st.nextToken());
            int m = Integer.parseInt(st.nextToken());
 
            conn.get(n).add(m);
            reconn.get(m).add(n);
        }
 
        for (int i = 1; i < N + 1; i++) { // 모든 정점에 대하여
            if (visit[i] == false) { // 방문한 노드를 제외하고
                dfs(i); // 순방향 그래프에 대한 dfs 실행
            }
        }
 
        Arrays.fill(visit, false); // 방문 여부를 체크할 visit 배열 초기화
 
        int num = 1;
        while (!stack.isEmpty()) { // 스택이 빌 때 까지
            int node = stack.pop();
 
            if (visit[node] == false) { // 이미 방문한 노드가 아니면
                redfs(node, num++); // 역방향 그래프에 대한 dfs 실행
            }
        }
 
        HashSet<Integer> hs = new HashSet<>(); // HashSet을 이용하여 몇 개의 scc가 존재하는지 파악
        for (int i = 1; i <= N; i++) {
            hs.add(scc[i]);
        }
        bw.write(String.valueOf(hs.size()) + "\n"); // scc의 갯수 출력
 
        Arrays.fill(visit, false);
        for (int i = 1; i <= N; i++) { // 각각의 scc에 속하는 노드들을 출력
            
            if (visit[i] == false) {
                int tmp = scc[i];
                visit[i] = true;
                bw.write(String.valueOf(i) + " ");
                for (int j = 1; j <= N; j++) {
                    if (i == j)
                        continue;
 
                    if (tmp == scc[j]) {
                        bw.write(String.valueOf(j) + " ");
                        visit[j] = true;
                    }
                }
                bw.write("-1\n");
            }
        }
 
        bw.flush();
        bw.close();
        br.close();
    }
}
 
cs
반응형

'백준 온라인 저지 > Platinum' 카테고리의 다른 글

[BOJ] 4196 - 도미노  (0) 2022.01.04