algorithms-shortest-path.md

🏑

Shortest Path : Bellman-Ford & Dijkstra (feat. μ‹œκ°„ λ³΅μž‘λ„, Bellman-Ford 예제)

BFS is not enough : Real edges has weights

  • 두 λ…Έλ“œ μ‚¬μ΄μ˜ κ°€μž₯ 짧은 거리λ₯Ό κ΅¬ν•˜λŠ” λ°©λ²•μ—λŠ” BFS, Bellman-Ford 벨만 ν¬λ“œ, Dijkstra λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜μ΄ μžˆμŠ΅λ‹ˆλ‹€.

0. BFS, Breath First Search

  • μ΅œλ‹¨ 거리 μš°μ„  탐색
  • edge의 κ°€μ€‘μΉ˜λ₯Ό 계산할 수 μ—†μŒ

1. Bellman-Ford algorithm

  • 음수λ₯Ό μ²˜λ¦¬ν•  수 있음

2. Dijkstra

  • 벨만 ν¬λ“œλ³΄λ‹€ 빠름
  • 음수λ₯Ό μ²˜λ¦¬ν•  수 μ—†μŒ

| μ•Œκ³ λ¦¬μ¦˜ | μ΅œλ‹¨ 경둜 탐색 방법 | 음수 κ°€μ€‘μΉ˜ 처리 | μ‹œκ°„ λ³΅μž‘λ„ (μ΅œμ•…μ˜ 경우) | | -------------------- | -------------------------- | --------------------- | ------------------------- | | Dijkstra | κ°€μž₯ μž‘μ€ κ°€μ€‘μΉ˜ μš°μ„  탐색 | 음수 κ°€μ€‘μΉ˜ 처리 λΆˆκ°€ | O((V + E) log V) | | Bellman-Ford | λͺ¨λ“  간선을 μˆœνšŒν•˜λ©° 탐색 | 음수 κ°€μ€‘μΉ˜ 처리 κ°€λŠ₯ | O(VE) | | BFS (λ„ˆλΉ„ μš°μ„  탐색) | μ΅œλ‹¨ 거리 μš°μ„  탐색 | 음수 κ°€μ€‘μΉ˜ 처리 λΆˆκ°€ | O(V + E) |

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

μ‹œκ°„ λ³΅μž‘λ„λŠ” μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹€ν–‰ 속도λ₯Ό λ‚˜νƒ€λ‚΄λŠ” μ§€ν‘œμž…λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„κ°€ μž‘μ„μˆ˜λ‘ μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹€ν–‰ 속도가 λΉ λ¦…λ‹ˆλ‹€

O, n, V, Eλž€?

| μš©μ–΄ | μ˜μ–΄ | μ„€λͺ… | μ‚¬μš© | | ---------------------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------------ | -------------------- | | O | Order | μ•Œκ³ λ¦¬μ¦˜μ˜ μ‹œκ°„ λ³΅μž‘λ„λ₯Ό λ‚˜νƒ€λ‚΄λŠ” ν‘œκΈ°λ²• | | μ‹€ν–‰ μ‹œκ°„μ΄ μž…λ ₯ 크기에 λŒ€ν•΄ μ–΄λ–»κ²Œ μ¦κ°€ν•˜λŠ”μ§€λ₯Ό ν‘œν˜„ (μ΅œμ•…μ˜ 경우λ₯Ό λ‚˜νƒ€λƒ„) | μ•Œκ³ λ¦¬μ¦˜ μ‹œκ°„ λ³΅μž‘λ„ ν‘œκΈ° | | n | Input Size | μ•Œκ³ λ¦¬μ¦˜μ˜ μž…λ ₯ 크기λ₯Ό λ‚˜νƒ€λ‚΄λŠ” λ³€μˆ˜ | μ•Œκ³ λ¦¬μ¦˜μ˜ μž…λ ₯ 크기 | | V | Vertex | κ·Έλž˜ν”„μ—μ„œμ˜ 정점(Vertex)의 수, λ…Έλ“œ λ˜λŠ” 꼭짓점 | κ·Έλž˜ν”„μ˜ μš”μ†Œ | | E | Edge | κ·Έλž˜ν”„μ—μ„œμ˜ κ°„μ„ (Edge)의 수, κ·Έλž˜ν”„μ˜ Vertex 정점듀을 μ—°κ²°ν•˜λŠ” μ„  | κ·Έλž˜ν”„μ˜ μš”μ†Œ |

μ‹œκ°„ λ³΅μž‘λ„μ˜ μ˜ˆμ‹œ πŸ€”

| ν‘œκΈ°λ²• | μ½λŠ” 법 | μš©μ–΄ | μ˜μ–΄ 발음 | μ„€λͺ… | | ---------- | ------------------------ | -------------- | ----------------- | ------------------------------------------------- | | O(1) | O of one | μƒμˆ˜ μ‹œκ°„ | constant time | μž…λ ₯ 크기에 λ¬΄κ΄€ν•œ μ‹€ν–‰ μ‹œκ°„ | | O(log n) | O of log n | 둜그 μ‹œκ°„ | logarithmic time | 둜그 베이슀둜 μž…λ ₯ 크기에 λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(n) | O of n | μ„ ν˜• μ‹œκ°„ | linear time | μž…λ ₯ 크기에 μ§μ„ μ μœΌλ‘œ λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(n log n) | O of n log n | μ„ ν˜• 둜그 μ‹œκ°„ | linearithmic time | μž…λ ₯ 크기와 둜그 베이슀의 곱에 λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(n^2) | O of n squared | 이차 μ‹œκ°„ | quadratic time | μž…λ ₯ 크기의 μ œκ³±μ— λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(n^3) | O of n cubed | μ‚Όμ°¨ μ‹œκ°„ | cubic time | μž…λ ₯ 크기의 μ„Έμ œκ³±μ— λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(2^n) | O of 2 to the power of n | μ§€μˆ˜ μ‹œκ°„ | exponential time | 2의 μž…λ ₯ 크기 μ œκ³±μ— λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ | | O(n!) | O of n factorial | νŒ©ν† λ¦¬μ–Ό μ‹œκ°„ | factorial time | μž…λ ₯ 크기의 νŒ©ν† λ¦¬μ–Όμ— λΉ„λ‘€ν•˜λŠ” μ‹€ν–‰ μ‹œκ°„ |

Dijkstra vs Bellman-Ford vs BFS πŸ”₯

  1. Dijkstra μ•Œκ³ λ¦¬μ¦˜:
    • μ‹œκ°„ λ³΅μž‘λ„: O((V + E) log V)
    • Dijkstra μ•Œκ³ λ¦¬μ¦˜μ€ κ°€μž₯ μž‘μ€ κ°€μ€‘μΉ˜λ₯Ό μš°μ„ μœΌλ‘œ μ„ νƒν•˜μ—¬ μ΅œλ‹¨ 경둜λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„ O((V + E) log V)λŠ” μ •μ μ˜ 수 V와 κ°„μ„ μ˜ 수 E에 따라 μ„ ν˜•μ μœΌλ‘œ μ¦κ°€ν•©λ‹ˆλ‹€. μ•Œκ³ λ¦¬μ¦˜μ΄ 정점을 νƒμƒ‰ν•˜κ³  κ°€μ€‘μΉ˜λ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” κ³Όμ •μ—μ„œ μš°μ„ μˆœμœ„ 큐λ₯Ό μ‚¬μš©ν•˜μ—¬ μ΅œμ†Œκ°’μ„ μΆ”μΆœν•˜κΈ° λ•Œλ¬Έμ— log V의 μ‹œκ°„ λ³΅μž‘λ„κ°€ μΆ”κ°€λ©λ‹ˆλ‹€.
  2. Bellman-Ford μ•Œκ³ λ¦¬μ¦˜:
    • μ‹œκ°„ λ³΅μž‘λ„: O(VE)
    • Bellman-Ford μ•Œκ³ λ¦¬μ¦˜μ€ λͺ¨λ“  간선을 μˆœνšŒν•˜λ©° μ΅œλ‹¨ 경둜λ₯Ό νƒμƒ‰ν•©λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„ O(VE)λŠ” μ •μ μ˜ 수 V와 κ°„μ„ μ˜ 수 E에 λΉ„λ‘€ν•˜μ—¬ μ¦κ°€ν•©λ‹ˆλ‹€. μ•Œκ³ λ¦¬μ¦˜μ΄ 간선을 μˆœνšŒν•˜λ©° μ΅œλ‹¨ 거리λ₯Ό κ°±μ‹ ν•˜λŠ” 과정을 V-1번 λ°˜λ³΅ν•˜κΈ° λ•Œλ¬Έμ— VE의 μ‹œκ°„ λ³΅μž‘λ„κ°€ λ°œμƒν•©λ‹ˆλ‹€.
  3. BFS (λ„ˆλΉ„ μš°μ„  탐색):
    • μ‹œκ°„ λ³΅μž‘λ„: O(V + E)
    • BFS μ•Œκ³ λ¦¬μ¦˜μ€ μ΅œλ‹¨ 거리 μš°μ„ μœΌλ‘œ νƒμƒ‰ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. μ‹œκ°„ λ³΅μž‘λ„ O(V + E)λŠ” μ •μ μ˜ 수 V와 κ°„μ„ μ˜ 수 E에 μ„ ν˜•μ μœΌλ‘œ μ¦κ°€ν•©λ‹ˆλ‹€. μ•Œκ³ λ¦¬μ¦˜μ΄ λ„ˆλΉ„ μš°μ„ μœΌλ‘œ 정점을 νƒμƒ‰ν•˜λŠ” κ³Όμ •μ—μ„œ λͺ¨λ“  정점과 간선을 ν•œ λ²ˆμ”©λ§Œ λ°©λ¬Έν•˜λ―€λ‘œ V + E의 μ‹œκ°„ λ³΅μž‘λ„κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

bellman-Ford Algorithm

  • 벨만 ν¬λ“œ - μžλ°”μŠ€ν¬λ¦½νŠΈ μ˜ˆμ‹œ ν™•μΈν•˜κΈ° + 주석 달기

    // κ·Έλž˜ν”„μ˜ 간선을 ν‘œν˜„ν•˜λŠ” 클래슀
    class Edge {
      constructor(source, destination, weight) {
    		// ν˜„μž¬ κ°„μ„ μ˜ 좜발 정점
        this.source = source;
    		// ν˜„μž¬ κ°„μ„ μ˜ 도착 정점
        this.destination = destination;
    		// κ°€μ€‘μΉ˜
        this.weight = weight;
      }
    }
    
    // 벨만 ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜ ν•¨μˆ˜
    function bellmanFord(graph, start) {
      const numVertices = graph.length; // κ·Έλž˜ν”„μ˜ 길이
    	const distances = new Array(numVertices).fill(Infinity); // μ΅œλ‹¨ 거리λ₯Ό μ €μž₯ν•˜κΈ° μœ„ν•œ λ°°μ—΄ μ΄ˆκΈ°ν™”
    
      distances[start] = 0;
    
      // μ‹œμž‘ 정점뢀터 (μ •μ μ˜ 개수 - 1)번 반볡
      for (let i = 0; i < numVertices - 1; i++) {
        // 이쀑 for문으둜 κ·Έλž˜ν”„μ˜ λͺ¨λ“  간선을 탐색
    		// μ‹œμž‘ μ •μ μœΌλ‘œλΆ€ν„° λ‹€λ₯Έ μ •μ κΉŒμ§€μ˜ μ΅œλ‹¨ 거리λ₯Ό μ°¨λ‘€λŒ€λ‘œ 계산
        for (let j = 0; j < graph.length; j++) {
          const edge = graph[j];
          const { source, destination, weight } = edge;
    
          // ν˜„μž¬ κ°„μ„ μ˜ 좜발 정점을 거쳐 도착 μ •μ κΉŒμ§€μ˜ 거리λ₯Ό κ³„μ‚°ν•˜μ—¬ μ΅œμ†Œκ°’μœΌλ‘œ κ°±μ‹ 
    			// [κ°„μ„ μ˜ κ°€μ€‘μΉ˜]
          if (distances[source] + weight < distances[destination]) {
    				// ν˜„μž¬κΉŒμ§€ μ•Œλ €μ§„ μ΅œλ‹¨ 거리보닀 더 짧은 경둜λ₯Ό μ°Ύμ•˜μ„ λ•Œ ν•΄λ‹Ή μ •μ κΉŒμ§€μ˜ 거리λ₯Ό κ°±μ‹ ν•˜λŠ” μž‘μ—…
            distances[destination] = distances[source] + weight
          }
    			// μ•Œκ³ λ¦¬μ¦˜μ΄ μ μ§„μ μœΌλ‘œ μ΅œλ‹¨ 거리λ₯Ό μ—…λ°μ΄νŠΈ
        }
    		// λ”°λΌμ„œ distances[destination]λŠ” μ΅œλ‹¨ 경둜  }
    
      // 음수 사이클 검사
      for (let i = 0; i < graph.length; i++) {
        const edge = graph[i];
        const { source, destination, weight } = edge;
    
        // 음수 사이클이 μ‘΄μž¬ν•˜λ©΄ μ΅œλ‹¨ 거리가 κ³„μ†ν•΄μ„œ κ°±μ‹ 
        if (distances[source] + weight < distances[destination]) {
          console.log("음수 사이클이 μ‘΄μž¬ν•©λ‹ˆλ‹€.");
          return;
        }
      }
    
      return distances; // μ΅œλ‹¨ 거리 배열을 λ°˜ν™˜
    }
    
    // κ·Έλž˜ν”„ 생성 및 μ˜ˆμ‹œ μ‹€ν–‰
    const graph = [
      new Edge(0, 1, 4),
      new Edge(0, 2, 3),
      new Edge(1, 3, 2),
      new Edge(1, 2, -5), // 음수 κ°€μ€‘μΉ˜ μ˜ˆμ‹œ
      new Edge(2, 4, 1),
      new Edge(3, 4, 4)
    ]
    
    const startVertex = 0;
    const shortestDistances = bellmanFord(graph, startVertex);
    console.log("μ΅œλ‹¨ 거리 λ°°μ—΄:", shortestDistances); // μ΅œλ‹¨ 거리 λ°°μ—΄: [0, 4, 3, 5, 6]
    

Next