๊ธ€ ์ž‘์„ฑ์ž: ๊ฐœ๋ฐœํ•˜๋Š” ํ›ˆ์ด

Strongly Connected Component

๊ฐ•ํ•œ ์—ฐ๊ฒฐ ์š”์†Œ(SCC) ๋ผ๊ณ ๋„ ํ•˜๋Š” Strongly Connected Component ๋Š” ๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์กฐ๊ฑด์ด ์„ฑ๋ฆฝํ•˜๋Š” ์ •์ ๋“ค์˜ ์ง‘ํ•ฉ์ด๋‹ค.

  1. SCC ๋‚ด์— ์žˆ๋Š” ์–ด๋–ค ๋‘ ์ •์ ์— ๋Œ€ํ•œ ๊ฒฝ๋กœ๊ฐ€ ํ•ญ์ƒ ์กด์žฌํ•œ๋‹ค. ์ฆ‰, ์‚ฌ์ดํด์ด ์กด์žฌํ•œ๋‹ค.
  2. ์„œ๋กœ ๋‹ค๋ฅธ SCC์— ์†ํ•˜๋Š” ๋‘ ์ •์ ์€ ์„œ๋กœ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์—†๋‹ค. ์ฆ‰, SCC ๊ฐ„์—๋Š” ์‚ฌ์ดํด์ด ์กด์žฌํ•  ์ˆ˜ ์—†๋‹ค.

 

์œ„์™€ ๊ฐ™์€ ๊ทธ๋ž˜ํ”„์—์„œ {A, B, C}, {C, D}, {F, G}, {H} ๋„ค ๊ฐœ์˜ Strongly Connected Component ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

Algorithm

๊ทธ๋ž˜ํ”„์—์„œ Strongly Connected Graph๋ฅผ ์ฐพ๋Š” ๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ ๋ˆˆ์œผ๋กœ ํ•œ๋ฒˆ์— ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ๋Š” ์กฐ๊ธˆ ๋‹ค๋ฅด๋‹ค. ๋งŒ์•ฝ ์ •์ ์ด ๊ต‰์žฅํžˆ ๋งŽ์€ ๊ทธ๋ž˜ํ”„๊ฐ€ ์ฃผ์–ด์กŒ๋‹ค๋ฉด ์–ด๋–ค ๋ฐฉ๋ฒ•์œผ๋กœ ์ปดํ“จํ„ฐ๊ฐ€ SCC ๋ฅผ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ์ง€๋งŒ, ์ •์„์ ์ธ ๋ฐฉ๋ฒ•์€ DFS๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

Applying DFS

DFS๋ฅผ ์ด์šฉํ•ด์„œ SCC๋ฅผ ์ฐพ์„ ๋•Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ๊ฑฐ์นœ๋‹ค.

  1. DFS ๋กœ ๊ฐ ์ •์ ์˜ finish time์„ ๊ธฐ๋กํ•œ๋‹ค.
  2. ํ˜„์žฌ ๊ทธ๋ž˜ํ”„๋ฅผ Transpose ํ•œ๋‹ค. ์ฆ‰, ๊ฐ Edge์˜ ๋ฐฉํ–ฅ์„ ๋ฐ˜๋Œ€๋กœ ์ทจํ•œ๋‹ค.
  3. Transposeํ•œ ๊ทธ๋ž˜ํ”„์— ๋Œ€ํ•ด์„œ DFS๋ฅผ ์ ์šฉํ•˜์—ฌ ๊ทธ๋ž˜ํ”„ ๋‚ด์— ์žˆ๋Š” ๋ชจ๋“  ํŠธ๋ฆฌ๋ฅผ ์ฐพ์•„์ค€๋‹ค. ์ด๋•Œ, ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ธฐ ์‹œ์ž‘ํ•  ๋ฃจํŠธ ๋…ธ๋“œ๋Š” finish time์ด ๊ฐ€์žฅ ๋Šฆ์€ ์ •์  ์ˆœ์œผ๋กœ ์ง„ํ–‰์ด ๋œ๋‹ค.

Proof

์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋ฌด์ฒ™์ด๋‚˜ ๊ฐ„๋‹จํ•ด๋ณด์ด๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ๋ฐฉ๋ฒ•์œผ๋กœ SCC๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ• ๊นŒ?

Lemma 1

์–ด๋–ค ๋‘ SCC X ์™€ Y๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜์ž. ๋งŒ์•ฝ X์— ์†ํ•œ ์ •์ ์ธ u ๊ฐ€ Y์— ์†ํ•˜๋Š” ์ •์  v์™€ ์ผ๋ฐฉํ–ฅ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๋ฉด, v๋Š” A์— ์†ํ•˜๋Š” ๋‹ค๋ฅธ ์–ด๋–ค ์ •์ ๊ณผ๋„ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์—†๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋งŒ์•ฝ v๊ฐ€ X์— ์†ํ•œ ์ •์  ์ค‘ ํ•˜๋‚˜๋ฅผ ๊ฐ€๋ฅดํ‚ค๊ฒŒ ๋˜๋ฉด ๋‘ SCC ์‚ฌ์ด์—๋Š” ์‚ฌ์ดํด์ด ์ƒ๊ธฐ๊ฒŒ ๋˜๊ณ , SCC์˜ ์„ฑ์งˆ์„ ์žƒ๊ฒŒ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

์œ„์™€ ๊ฐ™์€ ๋‘ SCC๋กœ ์ด๋ฃจ์–ด์ง„ ๊ทธ๋ž˜ํ”„๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•  ๋•Œ, ์ดˆ๋ก์ƒ‰ SCC์— ์†ํ•˜๋Š” B ๋…ธ๋“œ๊ฐ€ ๋…ธ๋ž€์ƒ‰ SCC์— ์†ํ•˜๋Š” F๋ฅผ ๊ฐ€๋ฅดํ‚ค๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์—์„œ F๊ฐ€ B๋ฅผ ๊ฐ€๋ฅดํ‚ค๋Š” edge๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋˜๋ฉด ์œ„ ๋‘ SCC ๋ชจ๋‘ ๋” ์ด์ƒ SCC๊ฐ€ ์•„๋‹ˆ๊ฒŒ ๋œ๋‹ค.

Lemma 2

๋”๋ถˆ์–ด์„œ, ๋งŒ์•ฝ ์–ด๋–ค ๋‘ SCC๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” edge ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, edge์˜ ์‹œ์ž‘์ ์— ์žˆ๋Š” SCC์˜ ์ •์ ๋“ค ์ค‘ ๊ฐ€์žฅ ๋Šฆ์€ finsh time์€ edge๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” SCC์˜ finish time ๋ณด๋‹ค ๋นจ๋ผ์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ finish time์€ ํ•œ SCC์— ์žˆ๋Š” ์ •์  ์ค‘ ํƒ์ƒ‰์ด ์™„์ „ํžˆ ๋๋‚˜๋Š”๋ฐ ๊ฐ€์žฅ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ๋…ธ๋“œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ด ์ •๋ฆฌ๋Š” ๋‹จ์ˆœํ•˜๊ณ  ๋‹น์—ฐํ•œ ๊ฒƒ์ธ๋ฐ, ํ•œ SCC์—์„œ ๋‹ค์Œ SCC๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ธธ์ด ํ•ญ์ƒ ํ•œ ๋ฐฉํ–ฅ์ด์–ด์•ผ ํ•œ๋‹ค๋Š” Lemma 1์˜ ์ •๋ฆฌ์— ์˜ํ•ด ์–ด๋–ค SCC๋Š” ํ•ญ์ƒ ๊ทธ SCC๊ฐ€ ๊ฐ€๋ฅดํ‚ค๋Š” SCC ์ด์ „์— ํƒ์ƒ‰๋  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

 

 

์ด ๊ทธ๋ฆผ์—์„œ๋„ B์—์„œ F๋กœ ์—ฐ๊ฒฐ๋˜๋Š” edge๊ฐ€ ์ผ๋ฐฉํ–ฅ์ด๊ธฐ ๋•Œ๋ฌธ์— {A, B, C}๋กœ ์ด๋ฃจ์–ด์ง„ SCC๊ฐ€ {F, G} ๋กœ ์ด๋ฃจ์–ด์ง„ SCC ๋ณด๋‹ค ํ•ญ์ƒ ๋จผ์ € ํƒ์ƒ‰๋œ๋‹ค.

Corollary

์ด์ œ ๊ฐ edge์— ์—ญ๋ฐฉํ–ฅ์„ ์ทจํ•ด์„œ transpose ๋œ ๊ทธ๋ž˜ํ”„๋กœ ๋ณ€ํ˜•์‹œ์ผœ๋ณด์ž. ์ด๋•Œ ์šฐ๋ฆฌ๋Š” ์•ž์„  ์ •๋ฆฌ์— ์˜ํ•ด์„œ ๋˜ ๋‹ค๋ฅธ ์ •๋ฆฌ๋ฅผ ๋„์ถœํ•ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. Lemma 2 ์—์„œ ์ •๋ฆฌํ–ˆ๋˜ ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด ์–ด๋–ค ๋‘ SCC A ์™€ B๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ, A์—์„œ B ๋ฐฉํ–ฅ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๋ฉด, SCC A์˜ ๋๋‚˜๋Š” ์‹œ๊ฐ„์ด ํ•ญ์ƒ SCC B ๊ฐ€ ๋๋‚˜๋Š” ์‹œ๊ฐ„๋ณด๋‹ค ์ž‘๋‹ค. ๋”ฐ๋ผ์„œ ๊ทธ๋ž˜ํ”„์— ์—ญ๋ฐฉํ–ฅ์„ ์ทจํ•˜๊ฒŒ ๋˜๋ฉด, ์ด edge๋Š” ๋ฐ˜๋Œ€๋ฐฉํ–ฅ์„ ๊ฐ€๋ฅดํ‚ค๊ฒŒ ๋˜๊ณ  ์ด์ œ SCC B๊ฐ€ ๋๋‚˜๋Š” ์‹œ๊ฐ„์ด SCC A๊ฐ€ ๋๋‚˜๋Š” ์‹œ๊ฐ„๋ณด๋‹ค ์ž‘์•„์งˆ ๊ฒƒ์ด๋‹ค.

 

 

์ด ๊ทธ๋ฆผ์—์„œ๋„ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. {F, G} ๋กœ ์ด๋ฃจ์–ด์ง„ SCC์˜ ํƒ์ƒ‰์ด ๋๋‚˜์•ผ {A, B, E} ๋กœ ์ด๋ฃจ์–ด์ง„ SCC๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด ์ •๋ฆฌ์— ์ด์–ด Lemma 1์— ์˜ํ•ด {A, B, E} ๋กœ ์ด๋ฃจ์–ด์ง„ SCC๋กœ๋ถ€ํ„ฐ {F, G} ๋กœ ์ด๋ฃจ์–ด์ง„ SCC๋กœ ์—ฐ๊ฒฐ๋˜๋Š” edge๊ฐ€ ์žˆ์„ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ ๋˜ํ•œ ์ฆ๋ช…๋œ๋‹ค.

Implementation

[๋ฐฑ์ค€ ์•Œ๊ณ ๋ฆฌ์ฆ˜] 2150๋ฒˆ: Strongly Connected Component

๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ ์œ„ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๋ณด์•˜๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค ์‰ฝ์ง€ ์•Š์•„์„œ ๊ตฌ๊ธ€๋ง์œผ๋กœ ๋กœ์ง์„ ๋” ๊ณต๋ถ€ํ•˜๋ฉด์„œ ํ’€์—ˆ๋‹ค. SCC์—์„œ ์ค‘์š”ํ•œ ์ ์€ ๋๋‚œ์‹œ๊ฐ„ ์ˆœ์„œ๋Œ€๋กœ ์—ญ๋ฐฉํ–ฅ ํƒ์ƒ‰์„ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ Topology Sort ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์ผ๋˜ ์ „๋žต์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•ด์„œ ๋๋‚˜๋Š” ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋…ธ๋“œ๋“ค์„ ์Šคํƒ์— ์Œ“์•„๋‘๊ณ , ์—ญ๋ฐฉํ–ฅ์œผ๋กœ ํƒ์ƒ‰ํ•  ๋•Œ๋Š” ์Šคํƒ์— ์žˆ๋Š” ๋…ธ๋“œ๋“ค์„ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด์„œ ๋ฃจํŠธ๋…ธ๋“œ๋กœ ์‚ผ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๊ตฌํ˜„ํ•˜๊ธฐ์— ๊ฐ„ํŽธํ•˜๋‹ค. ์—ญ๋ฐฉํ–ฅ์— ๋Œ€ํ•œ ํ‘œํ˜„์€ ์ตœ์ดˆ์— ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž…๋ ฅ์„ ๋ฐ›์„ ๋•Œ, ์ธ์ ‘๋…ธ๋“œ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด์„œ ์ •๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์œผ๋กœ์˜ ๋ฆฌ์ŠคํŠธ๋„ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

#include <cstdio>
#include <queue>
#include <vector>
#include <stack>
#include <algorithm>

using namespace std;

bool visited[10001];
vector<vector<int>> result;
vector<vector<int>> adj;
vector<vector<int>> adjTrans;

stack<int>stk;

void dfs(int root){
    visited[root] = true;
    for (int  i = 0 ; i < adj[root].size() ; i++){
        if (!visited[adj[root][i]]){
            dfs(adj[root][i]);
        }
    }
    stk.push(root);
}

void scc(int root){
    visited[root] = true;
    for (int  i = 0 ; i < adjTrans[root].size() ; i++){
        if (!visited[adjTrans[root][i]]){
            scc(adjTrans[root][i]);
            result.back().push_back(adjTrans[root][i]);
        }
    }
}

int main (){
    int V, E;

    scanf("%d %d", &V, &E);

    adj.resize(V+1);
    adjTrans.resize(V+1);

    for (int i = 0 ; i < E  ; i++){
        int a, b;
        scanf("%d %d", &a, &b);
        adj[a].push_back(b);
        adjTrans[b].push_back(a);
    }

    for (int i = 1 ; i <= V ; i++){
        if(!visited[i]){
            dfs(i);
        }
    }

    for (int i = 0 ; i <=V ; i++) visited[i] = false;

    while(!stk.empty()){
        if (!visited[stk.top()]){
            vector<int> temp(1);
            temp[0] = stk.top();
            result.push_back(temp);
            scc(stk.top());
        }
        stk.pop();
    }

    printf("%lu\n", result.size());

    for (int i = 0 ; i < result.size() ; i++){
        sort(result[i].begin(), result[i].end());
    }

    sort(result.begin(), result.end());
    for (auto v : result){
        for (auto i : v){
            printf("%d ", i);
        }
        printf("-1\n");
    }
}