article thumbnail image
Published 2021. 7. 28. 18:27

문제 설명

문제 링크

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

 

4196번: 도미노

도미노는 재밌다. 도미노 블록을 일렬로 길게 늘어세운 뒤 블록 하나를 넘어뜨리면 그 블록이 넘어지며 다음 블록을 넘어뜨리는 일이 반복되어 일렬로 늘어선 블록들을 연쇄적으로 모두 쓰러

www.acmicpc.net

풀이

이 문제는 SCC를 이용하여 풀 수 있다.

처음에 이 문제를 보고 아무 점에서나 dfs를 돌려서 dfs를 몇 번 돌리나 카운팅 하면 될 것이라고 생각했다. 하지만 1 -> 2 -> 3 -> 4가 있을 때 1번에서 dfs가 시작하면 문제가 없지만 2, 3, 4번에서 dfs가 시작하면 1번은 처리가 되지 않는다. 

그렇기 때문에 SCC를 활용해야한다. 코사라주 알고리즘을 이용하면 stack의 최상단에는 항상 위의 예시에서 1과 같은 가장 연결이 많이 되어 있는 노드가 존재한다. 그렇기 때문에 stack에 저장된 모든 정점을 하나씩 꺼내며 dfs를 돌면 이 문제를 해결할 수 있다.

코드

#include <cstdio>
#include <vector>
#include <cstring>
#include <stack>

using namespace std;

bool visited[100005];
vector<vector<int>> v;
stack<int> s;

void dfs(int cur) {
    visited[cur] = true;
    for (auto nxt : v[cur]) {
        if (!visited[nxt]) dfs(nxt);
    }
    s.push(cur);
}

void solve() {
    int n, m; scanf("%d %d", &n, &m);
    v.clear(); v.resize(n + 1);
    while (m--) {
        int a, b; scanf("%d %d", &a, &b);
        v[a].push_back(b);
    }

    memset(visited, 0, sizeof visited);
    for (int i = 1; i <= n; i++) {
        if (!visited[i]) dfs(i);
    }

    memset(visited, 0, sizeof visited);    
    int ans = 0;
    while (!s.empty()) {
        int cur = s.top();
        s.pop();
        if (!visited[cur]) {
            dfs(cur);
            ans++;
        }
    }
    printf("%d\n", ans);
}

int main() {
    int t; scanf("%d", &t);
    while (t--) {
        solve();
    }
}

'Algorithm > BOJ' 카테고리의 다른 글

백준[4013] ATM  (0) 2021.07.30
백준[3977] 축구 전술  (0) 2021.07.29
백준[2150] Strongly Connected Compoment  (0) 2021.07.28
백준[13511] 트리와 쿼리 2  (0) 2021.07.25
백준[3176] 도로 네트워크  (0) 2021.07.25
복사했습니다!