SCC

백준 4196번 도미노 문제풀이

[4196 도미노] https://www.acmicpc.net/problem/4196 .
SCC를 이용하여 서로 영향을 미치지 않는 것의 개수를 구해보자!

SCC를 배우니까 플레 문제들이 쓱삭 풀린다.
SCC구하는 알고리즘으로는 타잔 알고리즘, 코사라주 알고리즘이 대표적인데 나는 아직 코사라주밖에 다루지 못한다.
공부할라면 하는데 귀찮쓰.. ㅋㅋㅋㅋ
코사라주 알고리즘은 SCC구하고 위상정렬 순으로 되어있어서 개꿀이다.

문제상황 파악하기.

매우 직관적인 문제이다.
x, y가 주어지는데 x가 쓰러지면 y도 쓰러진다는 것이다.
방향그래프로 나타낼 수 있고, 방향그래프 하면 SCC가 떠오른다.
SCC 중에서 indegree가 0인, 즉 SCC의 시작점이라고 할 수 있는 것의 개수만 구하면 된다.

SCC가 뭐길래?

Strongly Connected Component(강한 연결 요소)이다.
방향 그래프에서 사이클(cycle)이 있다면 그 사이클안에서는 맘껏 돌아 다닐 수 있다.
그 때 그 사이클 한 덩이를 SCC라고 한다.
즉, 모든 정점이 서로 이동 할 수 있는 상태 하나라는 것이다.

아이디어 얻기.

일단 SCC를 구하면 그 SCC들 사이에는 DAG(사이클이 없는 방향그래프)가 된다.
그러면 1번 SCC부터 dfs를 돌면서 dfs를 돌때마다 cnt해주면 답이된다.
1번부터 검사해도 되는 이유는 코사라주가 위상정렬 순으로 SCC를 내놓기 때문이다.

주의할 점

난 이거 메모리초과가 계속 나서 뭐지? 했는데 알고보니 DFS2함수에서 here에서 next로 가야하는데 here에서 here로 갔다 ….ㄷㄷ 시간 초과또는 틀렸습니다면 빨리 발견했을 것 같은데 메모리 초과라서 발견하는데 오래걸렸다.
오타는 항상조심하자 ㅠㅠ
테스트케이스마다 그래프를 잘 초기화 해주는 것말고는 주의 할 것이 별로 없다.

실제 코드

나머지 주의 할 점은 코드에 주석으로 처리했다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#include <cassert>
#define fast_io cin.tie(NULL); ios_base::sync_with_stdio(false);
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int MAX = 100001;
int n, m;
vector<int> G[MAX], R[MAX],DAG[MAX], C, order;
vector<bool> visited;

void DFS1(int here){
    C[here] = -1;
    for(int next : G[here]){
        if(!C[next]) DFS1(next);
    }
    order.push_back(here);
}

void DFS2(int here, int color){
    C[here] = color;
    for(int next : R[here]){
        if(C[next]==-1) DFS2(next, color);
    }
}

int SCC(){
    C = vector<int> (n+1,0);
    for(int i=1;i<=n;i++) if(!C[i]) DFS1(i);
    reverse(order.begin(), order.end());
    int cnt = 0;
    for(int i : order) if(C[i]==-1) DFS2(i, ++cnt);
    return cnt;
}

void dfs(int here){
    visited[here] = true;
    for(int next : DAG[here]){
        if(!visited[next]){
            dfs(next);
        }
    }
}

int main(){
    fast_io;
    int tt; cin >> tt;
    while (tt--) {
        cin >> n >> m;
        for(int i=0;i<m;i++){
            int u, v; cin >> u >> v;
            G[u].push_back(v);
            R[v].push_back(u);
        }
        int SCCcnt = SCC();
        for(int i=1;i<=n;i++){
            for(int next : G[i]){
                if(C[i]==C[next]) continue;
                DAG[C[i]].push_back(C[next]);
            }
        }
        int res = 0;
        visited = vector<bool> (SCCcnt+1, false);
        for(int i=1;i<=SCCcnt;i++){
            if(!visited[i]){
                dfs(i);
                res++;
            }
        }
            
        cout << res << '\n';
        for(int i=0;i<MAX;i++){
            G[i].clear();
            R[i].clear();
            DAG[i].clear();
        }
        order.clear();
    }
}

Leave a comment

2024

D&C Optimization

3 minute read

분할정복을 이용한 다이나믹 프로그래밍 최적화

Back to top ↑

2023

Back to top ↑

2022

Greedy

2 minute read

백준 18186번 라면사기(large) 문제풀이

SCC

2 minute read

백준 4196번 도미노 문제풀이

LCA

2 minute read

백준 3176번 도로 네트워크 문제풀이

2-SAT

2 minute read

백준 16367번 TV Show Game 문제풀이

Hashing

2 minute read

백준 21162번 뒤집기 K 문제풀이

Tree DP

1 minute read

백준 1949번 우수 마을 문제풀이

Trie

1 minute read

Trie 자료구조 이해하기

Merge Sort

1 minute read

merge sort를 이용하여 inversion 개수세기

Segment Tree

2 minute read

백준 11505 구간 곱 구하기 문제풀이

BFS

1 minute read

백준 2206 벽 부수고 이동하기 문제풀이

기하

1 minute read

백준 2166 다각형의 면적 문제풀이

이분탐색

1 minute read

백준 12015 가장 긴 증가하는 부분 수열2 문제풀이

누적 합

1 minute read

백준 10986 나머지합 문제풀이

Stack

1 minute read

스택 구현하기 ========== 자료구조의 기본이라고 하면 스택 과 큐가 있다 백준 10828번에서 마주친 스택

정렬1

1 minute read

매우매우 많은 정렬이 있지만 그중 가장 안 어려운 3가지를 공부해보았다.

Back to top ↑