반응형

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

 

 

[ 문제풀이 ]

 

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다!!

https://rudalsd.tistory.com/74?category=1064608 

 

[ 소스 코드 ]

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
#include<iostream>
#include<stack>
#include<vector>
#include<algorithm>
 
using namespace  std;
 
int V, E;
vector<int> list[10001];        //그래프 저장할 배열
int id[10001];                    //방문할 순서를 저장할 배열
int seq = 1;                    //방문한 순서
int fin[10001];                    //scc 여부
stack<int> s;
vector<vector<int>> ans;        //scc들을 저장할 배열
 
int dfs(int cur)
{
    id[cur] = seq++;
    int ret = id[cur];
    s.push(cur);
 
    for (int i = 0; i < list[cur].size(); i++) {
        int next = list[cur][i];
        if (id[next] == 0) {        //한번도 방문하지 않았다면
            ret = min(ret, dfs(next));    //부모 중 가장 작은 id값을 ret에 저장
        }
        else if (fin[next] == 0) {    //방문했을 때 아직 scc가 아니라면
            ret = min(ret, id[next]);    //부모 중 가장 작은 id값을 ret에 저장
        }
    }
 
    if (ret == id[cur]) {        //부모 중 가장 작은 id값과 본인의 id값이 일치한다면
        vector<int> scc;
        while (1) {
            int top = s.top();    //stack에서 빼주면서
            fin[top] = 1;
            scc.push_back(top);    //scc에 push
            s.pop();
            if (top == cur) {    //stack에서 본인을 만나면
                break;
            }
        }
        sort(scc.begin(), scc.end());
        ans.push_back(scc);
    }
    return ret;
}
 
int main()
{
    cin >> V >> E;
 
    for (int i = 0; i < E; i++) {
        int a, b;
        scanf("%d %d"&a, &b);
        list[a].push_back(b);
    }
    
    for (int i = 1; i <= V; i++) {
        if(id[i] == 0) dfs(i);
    }
    
 
    sort(ans.begin(), ans.end());
 
    printf("%d\n", ans.size());
    for (int i = 0; i < ans.size(); i++) {
        for (int j = 0; j < ans[i].size(); j++) {
            printf("%d ", ans[i][j]);
        }
        printf("-1\n");
    }
}
cs
반응형
반응형

1. 강한 연결 요소 추출 알고리즘(Strongly Connected Component)이란?

 

방향성이 존재하는 그래프에서 모든 정점이 다른 모든 정점들에 대하여 방문할 수 있는 경우 즉, 그 부분집합에 들어있는 서로 다른 임의의 두 정점 u, v에 대해서 u에서 v로 가는 경로와 v에서 u로 가는 경로가 모두 존재하는 경우를 말합니다.

 

 

2. 강한 연결 요소 추출 알고리즘(Strongly Connected Component)동작 원리?

 

dfs를 활용하여 O(V+E)의 시간복잡도로 문제를 해결할 수 있습니다. 코사라주 알고리즘과 타잔 알고리즘이 있지만 그 중 더 빠른 타잔 알고리즘을 통해 SCC를 찾겠습니다.

 

 

위 그래프의 방문 순서에 따라 id값을 매깁니다. id값은 0부터 시작하며 1씩 증가합니다. 방문 순서는 0→1→2→3→4→5→6→7이 되며 방문할 때마다 해당 정점을 스택에 집어 넣습니다.

 

각 정점에 대하여 dfs를 수행하여 SCC를 추출해보겠습니다. SCC의 발견 조건은 '자신의 자식 노드(id값이 상대적으로 높을 때)들이 본인의 부모 노드(id값이 상대적으로 낮을 때)로 갈 수 있는 경우의 수가 없는 경우' 이며 이때 스택에서 본인보다 위에 있는 모든 노드들을 빼주고 scc에 넣어주면 됩니다.

 

stack

 

7번 노드는 돌아갈 수 있는 부모 노드가 없으므로 SCC 발견 조건을 만족합니다. 따라서 stack에서 본인이 나올 때까지 숫자를 뽑습니다. stack의 top이 현재 7이므로 7만 빼서 ans에 넣고 계속 진행합니다.

 

stack

 

다시 6번 노드에서 4번 노드로 가면 4번 노드는 더 이상 부모 노드로 갈 수 없습니다. 따라서 stack에서 4가 나올 때까지 숫자를 뽑아줍니다.

 

stack

 

마지막으로 3번 노드에서 0번 노드로 가고 0번 노드는 더이상 부모 노드가 없기 때문에 stack에서 0이 나올 때까지 숫자를 뽑아줍니다.

 

stack

 

모든 SCC를 발견해서 스택이 비었고, 결과적으로 3개의 SCC가 나옵니다.

 

이 알고리즘을 이용하여 다음 문제를 풀 수 있습니다.

https://rudalsd.tistory.com/75

 

반응형

+ Recent posts