🚦 μœ„μƒ μ •λ ¬

경이·2024λ…„ 12μ›” 4일
post-thumbnail

🚦 μœ„μƒ μ •λ ¬(Topology Sort)

  • μœ„μƒ 정렬은 λ°©ν–₯이 있고, μˆœν™˜ν•˜μ§€ μ•ŠλŠ” κ·Έλž˜ν”„μ—μ„œ 각 λ…Έλ“œλ₯Ό μˆœμ„œλŒ€λ‘œ λ‚˜μ—΄ν•˜λŠ” 방법이닀.
  • μ‰½κ²Œ 말해 μˆœμ„œκ°€ μ •ν•΄μ Έ μžˆλŠ” 일련의 μž‘μ—…λ“€μ„ μ°¨λ‘€λŒ€λ‘œ μˆ˜ν–‰ν•΄μ•Ό ν•  λ•Œ μ‚¬μš©ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜μ΄λ‹€.
  • μ „ν˜•μ μΈ μ˜ˆμ‹œλ‘œλŠ” β€œμ„ μˆ˜κ³Όλͺ© ꡬ쑰”가 μžˆλ‹€.
    • λ§Œμ•½ νŠΉμ • ꡐ과λͺ©μ— μ„ μˆ˜κ³Όλͺ©μ΄ μ‘΄μž¬ν•œλ‹€λ©΄ μ„ μˆ˜κ³Όλͺ©λΆ€ν„° μˆ˜κ°•μ„ ν•΄μ•Ό νŠΉμ • ꡐ과λͺ©μ„ μˆ˜κ°•ν•  수 μžˆλ‹€.
    • μ΄λ•Œ μœ„μƒμ •λ ¬μ„ μ‚¬μš©ν•˜λ©΄ μ˜¬λ°”λ₯Έ μˆ˜κ°• μˆœμ„œλ₯Ό μ°Ύμ•„λ‚Ό 수 μžˆλ‹€.

🚦 λ™μž‘ 원리

  1. μ§„μž…μ°¨μˆ˜κ°€ 0인 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.
  2. 큐가 빌 λ•ŒκΉŒμ§€ λ‹€μŒμ˜ 과정을 λ°˜λ³΅ν•œλ‹€.
    1. νμ—μ„œ μ›μ†Œλ₯Ό κΊΌλ‚΄ ν•΄λ‹Ή λ…Έλ“œμ—μ„œ μΆœλ°œν•˜λŠ” 간선을 κ·Έλž˜ν”„μ—μ„œ μ œκ±°ν•œλ‹€.
    2. μƒˆλ‘­κ²Œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

μœ„ 과정을 μˆ˜ν–‰ν–ˆμ„ λ•Œ 각 λ…Έλ“œκ°€ νμ—λ“€μ–΄μ˜¨ μˆœμ„œκ°€ μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ κ²°κ³Όκ°€ λœλ‹€.

μ§„μž…μ°¨μˆ˜λž€ ?
νŠΉμ •ν•œ λ…Έλ“œλ‘œ λ“€μ–΄μ˜€λŠ” κ°„μ„ μ˜ 개수

μœ„ 과정을 그림으둜 μ‚΄νŽ΄λ³΄μž!

μ§„μž…μ°¨μˆ˜ κ°€ 0인 λ…Έλ“œμΈ 1번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

νμ—μ„œ 1번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 1번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 2번 λ…Έλ“œ, 5번 λ…Έλ“œλ‘œ κ°€λŠ” κ°„μ„  λ‘κ°œλ₯Ό μ œκ±°ν•œλ‹€.

λ‹€μ‹œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 2번 λ…Έλ“œμ™€ 5번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€. 이 λ•Œ 큐에 λ„£λŠ” μˆœμ„œλŠ” 상관 μ—†λ‹€. μ–΄λ–€ λ…Έλ“œλ₯Ό λ¨Όμ € μˆ˜ν–‰ν•΄λ„ λ…Έλ“œλ₯Ό μˆœμ„œλŒ€λ‘œ λ°©λ¬Έν•˜λŠ” 것에 μœ„λ°˜λ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ΄λ‹€.

νμ—μ„œ 2번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 2번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 3번 λ…Έλ“œ, 6번 λ…Έλ“œλ‘œ κ°€λŠ” κ°„μ„  λ‘κ°œλ₯Ό μ œκ±°ν•œλ‹€.

λ‹€μ‹œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 3번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

νμ—μ„œ 5번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 5번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 6번 λ…Έλ“œλ‘œ κ°€λŠ” 간선을 μ œκ±°ν•œλ‹€.

λ‹€μ‹œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 6번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

νμ—μ„œ 3번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 3번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 4번 λ…Έλ“œλ‘œ κ°€λŠ” 간선을 μ œκ±°ν•œλ‹€.

μ§„μž…μ°¨μˆ˜κ°€ 0이 된 λ…Έλ“œκ°€ μ—†μœΌλ―€λ‘œ λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜μ–΄κ°„λ‹€.

νμ—μ„œ 6번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 6번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 4번 λ…Έλ“œλ‘œ κ°€λŠ” 간선을 μ œκ±°ν•œλ‹€.

λ‹€μ‹œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 4번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

νμ—μ„œ 4번 λ…Έλ“œλ₯Ό κΊΌλ‚Έ λ’€, 4번 λ…Έλ“œμ—μ„œ μΆœλ°œν•΄ 7번 λ…Έλ“œλ‘œ κ°€λŠ” 간선을 μ œκ±°ν•œλ‹€.

λ‹€μ‹œ μ§„μž…μ°¨μˆ˜κ°€ 0이 된 7번 λ…Έλ“œλ₯Ό 큐에 λ„£λŠ”λ‹€.

νμ—μ„œ 7번 λ…Έλ“œλ₯Ό κΊΌλ‚Έλ‹€. 7번 λ…Έλ“œμ—μ„œ λ‚˜κ°€λŠ” 간선이 μ—†κ³ , μ§„μž…μ°¨μˆ˜κ°€ 0이된 λ…Έλ“œκ°€ μ—†μœΌλ―€λ‘œ 순회λ₯Ό μ’…λ£Œν•œλ‹€.


각 λ…Έλ“œκ°€ 큐에 λ“€μ–΄μ˜¨ μˆœμ„œ, 즉 μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ κ²°κ³ΌλŠ” λ‹€μŒκ³Ό κ°™λ‹€.

1 β†’ 2 β†’ 5 β†’ 3 β†’ 6 β†’ 4 β†’ 7

λ§Œμ•½ μŠ€ν… 2μ—μ„œ 5번 λ…Έλ“œλ₯Ό λ¨Όμ € 넣어쀬닀면 μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ κ²°κ³ΌλŠ” λ‹€μŒκ³Ό 같을 것이닀.

1 β†’ 5 β†’ 2 β†’ 3 β†’ 6 β†’ 4 β†’ 7

이처럼 ν•œ λ‹¨κ³„μ—μ„œ 큐에 μƒˆλ‘­κ²Œ λ“€μ–΄κ°€λŠ” μ›μ†Œκ°€ 2개 이상인 경우 μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ κ²°κ³ΌλŠ” μ—¬λŸ¬κ°œκ°€ λœλ‹€.

λ˜ν•œ λͺ¨λ“  μ›μ†Œλ₯Ό λ°©λ¬Έν•˜κΈ° 전에 큐가 λΉˆλ‹€λ©΄ 사이클이 μ‘΄μž¬ν•œλ‹€κ³  νŒλ‹¨ν•  수 μžˆλ‹€. 사이클이 μžˆλŠ” 경우 사이클 λ‚΄μ˜ λ…Έλ“œλ“€μ€ μˆœμ„œλ₯Ό μ •ν•  수 없기에 μ–΄λ–€ λ…Έλ“œλ„ 큐도 λ“€μ–΄κ°ˆ μˆ˜κ°€ μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.


🚦 μ†ŒμŠ€μ½”λ“œ(JS)

// μž…λ ₯ κ°’ 첫 μš”μ†ŒλŠ” λ…Έλ“œμ˜ κ°œμˆ˜μ™€ κ°„μ„ μ˜ 개수
// 이후 n개의 μš”μ†ŒλŠ” κ°„μ„ μ˜ 정보(μ‹œμž‘ λ…Έλ“œ 끝 λ…Έλ“œ)
const inputs = ['7 8', '1 2', '1 5', '2 3', '2 6', '3 4', '4 7', '5 6', '6 4'];
const [n, e] = inputs.shift().split(' ').map(Number);

// κ·Έλž˜ν”„ κ°„μ„  정보λ₯Ό μ €μž₯ν•  λ°°μ—΄
const graph = Array.from({ length: n + 1 }, () => []);

// 각 λ…Έλ“œλ³„ μ§„μž… 차수λ₯Ό 계산할 λ°°μ—΄
const indegree = Array(n + 1).fill(0);
const q = [];

// κ°„μ„  정보λ₯Ό μˆœνšŒν•˜λ©° μ‹œμž‘ λ…Έλ“œμ™€ 끝 λ…Έλ“œλ₯Ό κ·Έλž˜ν”„μ— λ„£κ³ , μ§„μž…μ°¨μˆ˜λ₯Ό κ³„μ‚°ν•œλ‹€.
for (const input of inputs) {
  const [s, e] = input.split(' ').map(Number);

  graph[s].push(e);
  indegree[e] += 1;
}

// λͺ¨λ“  간선정보와 μ§„μž…μ°¨μˆ˜λ₯Ό μž…λ ₯받은 λ’€ μ§„μž…μ°¨μˆ˜κ°€ 0인 λ…Έλ“œλ₯Ό μ°Ύμ•„ 큐에 λ„£μ–΄μ€€λ‹€.
for (let i = 1; i <= n; i++) {
  if (indegree[i] === 0) q.push(i);
}

// 큐가 λΉŒλ•ŒκΉŒμ§€ 순회
while (q.length) {
  const current = q.shift();

  // 큐에 λ°©λ¬Έν•œ μˆœμ„œκ°€ μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ μˆœμ„œ
  // 즉 좜λ ₯λ˜λŠ” λ…Έλ“œ μˆœμ„œκ°€ μœ„μƒμ •λ ¬μ„ μˆ˜ν–‰ν•œ κ²°κ³Ό
  console.log(current);

  // ν˜„μž¬ λ…Έλ“œμ™€ μ—°κ²°λœ 간선을 μ œκ±°ν•¨
  for (const next of graph[current]) {
    indegree[next] -= 1;

    // μƒˆλ‘­κ²Œμ§„μž…μ°¨μˆ˜κ°€ 0인 λ…Έλ“œλ₯Ό 큐에 μ‚½μž…
    if (indegree[next] === 0) q.push(next);
  }
}

🚦 μ‹œκ°„ λ³΅μž‘λ„

μœ„μƒ μ •λ Ήμ˜ μ‹œκ°„λ³΅μž‘λ„λŠ” O(V + E)이닀. λͺ¨λ“  λ…Έλ“œλ₯Ό ν™•μΈν•˜κ³ , λͺ¨λ“  κ°„μ„ μ˜ ν™•μΈν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.


🚦 μœ„μƒμ •λ ¬ 문제 μΆ”μ²œ


🚦 Ref

profile
둝타λ₯΄μ˜€κ°€λ₯΄

0개의 λŒ“κΈ€