κ° μ°κ²° μ±λΆ(Strongly Connected Component)μ΄λ?
κ° μ°κ²° μ±λΆμ΄λ λ°©ν₯ κ·Έλνμμ μ°κ²° μ±λΆ λ΄μ μμμ λ μ μ uμ vμ λν΄μ uμμ vλ‘ κ°λ κ²½λ‘κ° μλ λμμ, vμμ uλ‘ λμμ€λ κ²½λ‘κ° μλ μ°κ²° μ±λΆμ΄λ€.
κ° μ°κ²° μ±λΆμ κ·Έ μ μμ νΉμ§ μ λ¨μ μ μ μ΄λ, λ€λ¦¬ κ°μ μ ν¬ν¨νμ§ μλλ°, μκ°ν΄λ³΄λ©΄ λΉμ°νλ€. κ° μ°κ²° μ±λΆ λ΄μ νΉμ μ μ μ μ κ±°ν¨μΌλ‘μ¨, λ κ° μ΄μμ μ°κ²° μ±λΆμΌλ‘ λλμ§λ μκ³ κ·Έλ¬ν κ°μ λ μ‘΄μ¬νμ§ μλλ€.
μλ κ·Έλ¦Όμ μ΄ν΄λ³΄λ©΄, κ·Έ μλ―Έλ₯Ό λμ± μ½κ² νμ ν μ μμ κ²μ΄λ€.
μμ΄ κ°μ μ μ λ€μ νλ² μ΄ν΄λ³΄λ©΄, μμμ λ μ μ μ λν΄μ μ€κ³ κ°λ κΈΈμ΄ μλ€λ κ²μ νμΈν μ μλ€. λ°λλ‘, μμ΄ λ€λ₯Έ μ μ λΌλ¦¬ μ€κ³ κ°λ €λ©΄, μ΄λ ν λ°©ν₯μ λ§νκ³ λ§λ€.
κΆκ·Ήμ μΌλ‘, SCCμ λͺ©νλ μ΄λ κ² μμ΄ κ°μ μ μ λ€μ μ§ν©μ μ°Ύμλ΄λ κ²μ΄λ€. λ€μλ§ν΄ κ·Έλνμμ κ° μ°κ²° μ±λΆμ μ°Ύμλ΄λ κ²μ΄λΌκ³ ν μ μλ€.
SCC μκ³ λ¦¬μ¦μ μ’ λ₯λ‘λ λ κ°μ§λ‘, Tarjan μκ³ λ¦¬μ¦, Kosarasu μκ³ λ¦¬μ¦μ΄ μλ€.
Kosarasu μκ³ λ¦¬μ¦μ μλ°©ν₯ κ·Έλν μ¬μ©νλ©° 2λ²μ DFSλ₯Ό κ±°μΉκ³ ,Tarjan μκ³ λ¦¬μ¦μ μ€νμ μ¬μ©νλ©°, 1λ²μ DFSλ₯Ό κ±°μΉλ€.
μ΄λ² ν¬μ€ν μμλ Kosarasu μκ³ λ¦¬μ¦κ³Ό Tarjan μκ³ λ¦¬μ¦μ ν΅ν΄ μμ½κ² κ° μ°κ²° μ±λΆμ μ°Ύμλ³Ό κ²μ΄λ€.
Kosarasu μκ³ λ¦¬μ¦ μ΄ν΄νκΈ°
Kosarasu μκ³ λ¦¬μ¦μ κ° μ°κ²° μ±λΆ(SCC)μ κ°λ κ³Ό μμ μ λ ¬μ λν΄ μκ³ μλ€λ©΄, μ½κ² ν°λν μ μλ μκ³ λ¦¬μ¦μ΄λ€.
μμ μ λ ¬μ λνμ¬ μ λͺ¨λ₯Έλ€λ©΄, μλ ν¬μ€ν μ ν΅ν΄ κ°λ μ μ΅λν λ€ λ³΄λ κ²μ μΆμ²νλ€.
[μκ³ λ¦¬μ¦] μμ μ λ ¬μ μ΄ν΄ν΄λ³΄μ.
* μ΄ κΈμ μκ³ λ¦¬μ¦μ κ΄ν΄ νμ΅νλ©° μ 리ν κΈμ λλ€. νλ¦° μ μ΄λ, κ³ μ³μΌ ν λΆλΆμ΄ μμΌλ©΄ μλ €μ£ΌμΈμ..! μμ μ λ ¬μ΄λ? μμ μ λ ¬μ΄λ(Topological Sort) : μ¬μ΄ν΄μ΄ μλ λ°©ν₯ κ·Έλν(Directed Acycl
devrepo.tistory.com
μμ μ λ ¬μ΄λΌ ν¨μ μ¬μ΄ν΄μ΄ μλ λ°©ν₯ κ·Έλνμμ μ μ μ μ ν μμλ‘ λνλΈ κ²μ΄λΌκ³ νμλ€. μ΄λ μ μ λ€ κ°μ μ°μ μμλ₯Ό λνλ΄κΈ° μν΄ μ¬μ©λλ€. λν μμ λ΄μ©μμ κ° μ°κ²° μ±λΆμ λ μ μ κ°μ μ€κ³ κ°λ λ°©ν₯μ΄ μ‘΄μ¬νλ€λ κ²μ μ°λ¦¬λ μκ³ μλ€.
Kosarasuμ ν΅μ¬ κ°λ μ λ°λ‘ μ΄ μμ μ λ ¬μ ν΅ν΄μ μ μ μ μ ν μμλ‘ λνλ΄κ³ , κΈ°μ‘΄μ κ·Έλνμ λ°©ν₯μ λ°λλ‘ λ€μ§μ μλ°©ν₯ κ·Έλνλ₯Ό μ¬μ©νλ κ²μ΄λ€. μ΄ν, μμ μ λ ¬μ μ μ μμλλ‘ κ° μ°κ²° μ±λΆμ μ°ΎκΈ° μμνλλ° μ΄λ μλ°©ν₯ κ·Έλνμμ ν΄λΉ λ°©ν₯μΌλ‘ μ΄λν λ κ° μ μλ μ μ λ€μ μΆλ ₯νλ©΄ λλ€.
κ° μ μλ μ μ λ€μ κ³§, μμ μ λ ¬μμ μ°Ύμ μ ν μμλ‘λ λ°©λ¬Έμ΄ κ°λ₯νλ©° κ·Έ μμμ λ°©ν₯μΌλ‘λ κ°λ₯νλ€λ μλ―Έμ΄κΈ°λ νλ€. μ¦, κ° μ μλ μ μ λ€μ΄λ κ° μ°κ²° μ±λΆμ λ§νλ€.
ν·κ°λ¦¬λ©΄ μλλ κ²μ΄ μμ μ λ ¬μ μμλλ‘ μ μ μ κ³ λ₯΄κ³ , κ·Έ μ μ μ΄ μμΉν μλ°©ν₯ κ·Έλνμμ μ€μ§μ μΌλ‘ κ° μ°κ²° μ±λΆμ΄ λλ μ μ λ€μ μ°Ύλ κ²μ΄λ€. μ΄λ DFSλ₯Ό μ¬μ©ν΄ μ μ μ μ°Ύμ μ μλ€.
κ΅³μ΄ μμ μ λ ¬μ μμλλ‘ κ³¨λΌμΌ νλλ? λΌλ μλ¬Έμ λ μκΈΈ μ μλ€. νμ§λ§ μμ μ λ ¬μ μμλλ‘ κ³ λ₯΄μ§ μλλ€λ©΄, κ° SCC λ΄λΆμμ μμ μ λ ¬ μμλ₯Ό μ§ν€μ§ λͺ»ν μ μλ€. κ²°κ΅ μμ μ λ ¬ μμλ₯Ό μ§ν€λ©° μ€κ³ κ°λ λ°©ν₯μ΄ μ‘΄μ¬ν¨μ λνλ΄μΌ νκΈ° λλ¬Έμ΄λ€.
λ€μλ§ν΄, μμ μ λ ¬μ μμλ μ°μ μμκ° μ ν΄μ§ μ μ λ€μ μμμ΄λ€. κ·Έ μμ μ체λ μ§ν€λ©° κ°μΌνλ€λ κ²μ μΌλν΄ λμ.
μμ κ°μ κ·Έλνκ° μλ€κ³ νμ. μ΄ κ·Έλνμμ μμ μ λ ¬μ S = [8 9 2 3 5 6 0 1 7 4] μ΄λ€. μ΄ μμ μ λ ¬ μμμ μμλλ‘ μλ°©ν₯ κ·Έλνμμ μλ SCCλ₯Ό μ°ΎμΌλ©΄ λλ€. μλ κ·Έλ¦Όμ νλ² λ³΄μ.
μ κ·Έλνλ κΈ°μ‘΄μ λ°©ν₯ κ·Έλνλ₯Ό μμΌλ‘ λ€μ§μ λ°©ν₯ κ·Έλνμ΄λ€. ν΄λΉ λ°©ν₯ κ·Έλνμμ κ²°κ΅ SCCλ₯Ό μ°Ύμ 건λ°, κ·Έ μμλ μμ μ λ ¬μ μμμ κΈ°λ°νλ€.
Sμμ 8μ΄ μμ μ λ ¬ λ΄μ κ°μ₯ μμμ΄λ―λ‘, 8λΆν° νμνλ©΄, 8-2-9 κ·Έ λ€μμ λμ€μ§ μλλ€.
κ·Έλ¬λ©΄ Sμμ λ¨μ μμλ S = [3 5 6 0 1 7 4] μ΄λ€. μ΄ν, 3λΆν° νμνλ©΄, 3-0-6 μ΄ λμ€λ©°, S = [5 1 7 4]κ° λλ€.
5λ₯Ό νμνλ©΄, 5λ§μ΄ λμ€λ©° S = [1 7 4]μ΄κ³ λλ¨Έμ§ κ°λ€μ κ·Έλλ‘ SCCκ° λλ€.
μ§κΈκΉμ§ λμ κ³Όμ μ νμ νμΌλ, ν λ² μ½λλ‘ λ΄λ³΄μ.
Kosarasu μκ³ λ¦¬μ¦ κ΅¬ννκΈ°
import java.util.*;
public class KosarajuSCC {
private int V;
private List<Integer>[] graph;
private List<List<Integer>> sccList;
public KosarajuSCC(int V) {
this.V = V;
this.graph = new ArrayList[V];
for (int i = 0; i < V; i++) {
graph[i] = new ArrayList<>();
}
this.sccList = new ArrayList<>();
}
public void addEdge(int u, int v) {
graph[u].add(v);
}
public List<List<Integer>> findSCCs() {
Stack<Integer> stack = new Stack<>();
boolean[] visited = new boolean[V];
// μμ μ λ ¬ λ§λ€κΈ°, μ΄λ DFS μνμ΄ λλ°λ¨.
for (int i = 0; i < V; i++) {
if (!visited[i]) {
fillOrder(i, stack, visited);
}
}
// μλ°©ν₯ κ·Έλν
List<Integer>[] reversedGraph = new ArrayList[V];
for (int i = 0; i < V; i++) {
reversedGraph[i] = new ArrayList<>();
}
for (int i = 0; i < V; i++) {
for (int v : graph[i]) {
reversedGraph[v].add(i);
}
}
Arrays.fill(visited, false);
// stackμ μμ μ λ ¬, μμμ λΆν° νλμ© λΉΌκ°λ©΄μ DFS μν
while (!stack.isEmpty()) {
int v = stack.pop();
if (!visited[v]) {
// sccμ λ§λ€μ΄μ§ κ° μ°κ²°μ±λΆ μΆκ°
List<Integer> scc = new ArrayList<>();
DFSUtil(reversedGraph, v, visited, scc);
sccList.add(scc);
}
}
return sccList;
}
// μμ μ λ ¬ λ§λ€κΈ° μν DFS
private void fillOrder(int u, Stack<Integer> stack, boolean[] visited) {
visited[u] = true;
for (int v : graph[u]) {
if (!visited[v]) {
fillOrder(v, stack, visited);
}
}
stack.push(u);
}
// sccλ₯Ό μ°ΎκΈ° μν DFS
private void DFSUtil(List<Integer>[] reversedGraph, int v, boolean[] visited, List<Integer> scc) {
visited[v] = true;
scc.add(v);
for (int i : reversedGraph[v]) {
if (!visited[i]) {
DFSUtil(reversedGraph, i, visited, scc);
}
}
}
public static void main(String[] args) {
KosarajuSCC g = new KosarajuSCC(5);
g.addEdge(1, 0);
g.addEdge(0, 2);
g.addEdge(2, 1);
g.addEdge(0, 3);
g.addEdge(3, 4);
List<List<Integer>> sccs = g.findSCCs();
for (List<Integer> scc : sccs) {
System.out.println(scc);
}
}
}
μμ μ€λͺ ν λ΄μ©κ³Ό μ£Όμμ΄ λ¬λ¦° λ΄μ©μ 보면, μ½κ² λ΄μ©μ μ΄ν΄ν μ μμ κ²μ΄λ€.
Tarjan μκ³ λ¦¬μ¦ μ΄ν΄νκΈ°
Tarjan μκ³ λ¦¬μ¦μ μ²μ λ°°μΈ λλ μμ Kosarasu μκ³ λ¦¬μ¦λ³΄λ€ μ΄λ ΅λ€κ³ νλλ°, κ°μΈμ μΌλ‘ μ΄μ€ μ°κ²° μμμ λν΄ μμ§νλ€λ©΄ λ μ½λ€κ³ μκ°νλ€. λν Tarjan μκ³ λ¦¬μ¦μ΄ kosarasu μκ³ λ¦¬μ¦ λ³΄λ€ μ μ©λ μ½λ€κ³ νλ€.
Tarjan μκ³ λ¦¬μ¦μ μμ Kosarasu μκ³ λ¦¬μ¦κ³Ό λ¬λ¦¬ DFSλ₯Ό νλ²λ§ νΈμΆνλ€. μ΄λ stackκ³Ό low κ°μ μ΄μ©νλ Tarjan μκ³ λ¦¬μ¦μ νΉμ§μ΄κΈ°λ νλ€.
μ΄ μκ³ λ¦¬μ¦μ ν΅μ¬μ lowλΌλ κ°μ μ¬μ©νλλ°, μ΄λ DFS ν λ μκΈ° μμ μ ν¬ν¨ν΄ λλ¬ν μ μλ λ Έλ IDκ° κ°μ₯ μμ κ°μ΄λ€.
μμ ν¬μ€ν μμ λ°°μ΄ μ΄μ€ μ°κ²° μμλ₯Ό μκ°ν΄λ³΄μ. μ΄λ DFS λ°©λ¬Έ μμλ₯Ό λ΄μ λ°°μ΄ dfsnumλ μ΄κΈ°μλ λμΌν κ°μΌλ‘ μ§μ λλ€. κ°μ μ΄μ€ μ°κ²° μμλΌλ¦¬λ μ΄ dfsnum μ€ κ°μ₯ μμ κ°μΈ lownumμΌλ‘ μ λ°μ΄νΈ ν κ²μ κΈ°μ΅ν μ μλ€. μ΄λ μ¬κ·μ μΌλ‘ λ°μλκ³ , μ²μ λ°©λ¬Έν μ μ μμ λ°μνλ€. λν μ¬μ΄ν΄μ΄ νμ±λ¨μΌλ‘ μΈν΄ μμ±λ λ¨μ μ μ μ ν΅ν΄ κ°μ λ€λ₯Έ μ΄μ€ μ°κ²° μμλ λ€λ₯Έ lownumμΌλ‘ μ§μ ν΄μ£Όμλ€.
[μκ³ λ¦¬μ¦] Biconnect Component : μ΄μ€ μ°κ²° μ±λΆ
μ΄μ€ μ°κ²° μ±λΆ(Biconnect Component)λ? μ΄μ€ μ°κ²° μ±λΆμ΄λ, 무방ν₯ κ·Έλνμ μ°κ²° μ±λΆμμ μμμ λ μ μ¬μ΄μ μ μ΄λ λ κ°μ λ¨μ κ²½λ‘κ° μ‘΄μ¬νλ μ°κ²° μ±λΆμ λ»νλ€. μ΄λ, μ°κ²° μ±λΆμ΄λ κ·Έ
devrepo.tistory.com
λ§μ°¬κ°μ§λ‘ Tarjanλ μ μ¬νλ€.
dfnλ λ°©λ¬Έμμμ΄λ©°, low κ°λ dfn μ€ κ°μ₯ μμ κ°μ μλ―Ένλ€. μ΄κΈ°μ μ μ λ°©λ¬Έ μμλ dfnκ³Ό lowκ°μ λμΌν κ°μΌλ‘ μ§μ νλ€. λν μ²μ λ°©λ¬Έν μ μ μμ κ°μ low κ°μΌλ‘ μ§μ λλ€.
μ°¨μ΄μ μ΄ μλ€λ©΄, μ¬μ΄ν΄μ νμ±νλ κ² λμ μ Stack μμ λ°©λ¬Έν μ μ λ€μ λ£μ΄ λλλ€. κ·Έλ¦¬κ³ νμ λμ€ Stackμ μμλ₯Ό λ§λλ€λ©΄ λ μ΄μ νμμ μ€μ§νλ©° lowλ₯Ό μ λ°μ΄νΈ ν λΏμ΄λ€. (μ¬μ€ μ μ¬μ΄ν΄μ νμ±νλ κ²κ³Ό κ°λ€κ³ λ³Έλ€.)
μ΄ν, SCCλ₯Ό μΆλ ₯νκΈ° μν΄ low[u]μ dfn[u]μ κ°μ΄ μΌμΉνλ κ²μ νμΈνλ€. μ΄λ SCCμ κ° μ€, μ²μ μ€νμ λ£μ κ°μμ SCCλ₯Ό λ½μλ΄κΈ° μν¨μ΄λ€.
κ·Έλ κ² λ½μλΈ SCCλ₯Ό SCCSλΌλ κ° μ°κ²° μ±λΆλ€μ λͺ¨μΌλ 리μ€νΈμ μΆκ°νλ©° μ§ννλ κ²μ΄λ€.
λ€μμΌλ‘ μμ μ½λλ₯Ό 보며 κ·Έ λμμ μ€μ§μ μΌλ‘ μ΄ν΄ν΄λ³΄μ.
Tarjan μκ³ λ¦¬μ¦ κ΅¬ννκΈ°
import java.util.*;
class TarjanAlgorithm {
private int sequence = 0;
private Stack<Integer> stack = new Stack<>();
private List<List<Integer>> graph;
private int[] dfn;
private int[] low;
private boolean[] inStack;
public List<List<Integer>> findStronglyConnectedComponents(List<List<Integer>> adjacencyList) {
int n = adjacencyList.size();
graph = adjacencyList;
dfn = new int[n];
low = new int[n];
inStack = new boolean[n];
Arrays.fill(dfn, -1);
Arrays.fill(low, -1);
List<List<Integer>> sccs = new ArrayList<>();
for (int u = 0; u < n; u++) {
if (dfn[u] == -1) {
stronglyConnected(u, sccs);
}
}
return sccs;
}
private void stronglyConnected(int u, List<List<Integer>> sccs) {
dfn[u] = low[u] = sequence++;
stack.push(u);
inStack[u] = true;
for (int w : graph.get(u)) {
if (dfn[w] == -1) {
stronglyConnected(w, sccs);
low[u] = Math.min(low[u], low[w]);
} else if (inStack[w]) {
low[u] = Math.min(low[u], dfn[w]);
}
}
if (low[u] == dfn[u]) {
List<Integer> scc = new ArrayList<>();
while (true) {
int x = stack.pop();
inStack[x] = false;
scc.add(x);
if (x == u) break;
}
sccs.add(scc);
}
}
public static void main(String[] args) {
List<List<Integer>> adjacencyList = new ArrayList<>();
int n = 6; // κ·Έλνμ μ μ μ
for (int i = 0; i < n; i++) {
adjacencyList.add(new ArrayList<>());
}
adjacencyList.get(0).add(1);
adjacencyList.get(1).add(2);
adjacencyList.get(2).add(0);
adjacencyList.get(2).add(3);
adjacencyList.get(3).add(4);
adjacencyList.get(4).add(5);
adjacencyList.get(5).add(3);
TarjanAlgorithm tarjan = new TarjanAlgorithm();
List<List<Integer>> sccs = tarjan.findStronglyConnectedComponents(adjacencyList);
for (List<Integer> scc : sccs) {
System.out.println("Strongly Connected Component:");
for (int vertex : scc) {
System.out.print(vertex + " ");
}
System.out.println();
}
}
}