🎯 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜ μ™„λ²½ κ°€μ΄λ“œ: 원리뢀터 음수 사이클 κ²€μΆœκΉŒμ§€ πŸš€

κΉ€μƒμš±Β·2024λ…„ 10μ›” 12일
post-thumbnail

벨만-ν¬λ“œ(Bellman-Ford) μ•Œκ³ λ¦¬μ¦˜μ€ 음수 κ°€μ€‘μΉ˜λ₯Ό κ°€μ§„ κ·Έλž˜ν”„μ—μ„œλ„ μ΅œλ‹¨ 경둜λ₯Ό 찾을 수 μžˆλŠ” μ•Œκ³ λ¦¬μ¦˜μœΌλ‘œ, λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜κ³Ό ν•¨κ»˜ μ΅œλ‹¨ 경둜 μ•Œκ³ λ¦¬μ¦˜μ˜ μ–‘λŒ€ μ‚°λ§₯을 이루고 μžˆμŠ΅λ‹ˆλ‹€. 이번 ν¬μŠ€νŠΈμ—μ„œλŠ” 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ˜ 원리, μ‹œκ°„ λ³΅μž‘λ„, λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜κ³Όμ˜ 비ꡐ, 음수 사이클 κ²€μΆœ 원리, μˆ˜ν–‰ κ³Όμ •, 그리고 파이썬 μ½”λ“œ κ΅¬ν˜„κΉŒμ§€ μžμ„Ένžˆ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

πŸ“š λͺ©μ°¨

  1. 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜ κ°œμš”
  2. μ•Œκ³ λ¦¬μ¦˜ 원리
  3. 음수 사이클 κ²€μΆœ 원리
  4. μ‹œκ°„ λ³΅μž‘λ„
  5. λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜κ³Όμ˜ 비ꡐ
  6. μˆ˜ν–‰ κ³Όμ •
  7. 파이썬 μ½”λ“œ κ΅¬ν˜„
  8. κ²°λ‘ 

1. 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜ κ°œμš” 🧐

벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ€ 단일 μΆœλ°œμ μ—μ„œ λͺ¨λ“  μ •μ κΉŒμ§€μ˜ μ΅œλ‹¨ 경둜λ₯Ό μ°ΎλŠ” μ•Œκ³ λ¦¬μ¦˜μž…λ‹ˆλ‹€. 특히, 음수 κ°€μ€‘μΉ˜λ₯Ό κ°€μ§„ 간선이 μ‘΄μž¬ν•˜λŠ” κ·Έλž˜ν”„μ—μ„œλ„ μ‚¬μš© κ°€λŠ₯ν•˜λ©°, 음수 사이클(Negative Cycle)의 쑴재 μ—¬λΆ€κΉŒμ§€ κ²€μΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

2. μ•Œκ³ λ¦¬μ¦˜ 원리 πŸ”

벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ€ λ‹€μŒκ³Ό 같은 μ›λ¦¬λ‘œ λ™μž‘ν•©λ‹ˆλ‹€:

  1. μ΄ˆκΈ°ν™”: 좜발 μ •μ μ˜ 거리λ₯Ό 0으둜 μ„€μ •ν•˜κ³ , λ‚˜λ¨Έμ§€ λͺ¨λ“  μ •μ μ˜ 거리λ₯Ό λ¬΄ν•œλŒ€(∞)둜 μ„€μ •ν•©λ‹ˆλ‹€.

  2. κ°„μ„  μ™„ν™”(Edge Relaxation):

    • λͺ¨λ“  간선에 λŒ€ν•΄ λ‹€μŒ 과정을 λ°˜λ³΅ν•©λ‹ˆλ‹€.

      for i from 1 to V - 1:
          for each edge (u, v) with weight w:
              if distance[u] + w < distance[v]:
                  distance[v] = distance[u] + w
    • 이 과정은 κ·Έλž˜ν”„μ˜ 정점 수(V) - 1번 λ°˜λ³΅λ©λ‹ˆλ‹€.

  3. 음수 사이클 κ²€μΆœ:

    • λͺ¨λ“  간선을 ν•œ 번 더 κ²€μ‚¬ν•˜μ—¬, 거리가 더 μ€„μ–΄λ“œλŠ” 간선이 μžˆλ‹€λ©΄ 음수 사이클이 μ‘΄μž¬ν•œλ‹€κ³  νŒλ‹¨ν•©λ‹ˆλ‹€.

      for each edge (u, v) with weight w:
          if distance[u] + w < distance[v]:
              Negative Cycle Detected 🚨

3. 음수 사이클 κ²€μΆœ 원리 ⚠️

음수 μ‚¬μ΄ν΄μ΄λž€?

  • 음수 사이클: 사이클을 κ΅¬μ„±ν•˜λŠ” κ°„μ„ λ“€μ˜ κ°€μ€‘μΉ˜ 합이 음수인 경우λ₯Ό λ§ν•©λ‹ˆλ‹€.
  • μ΄λŸ¬ν•œ 사이클이 μ‘΄μž¬ν•˜λ©΄, λ¬΄ν•œνžˆ μž‘μ€ μ΅œλ‹¨ 거리λ₯Ό λ§Œλ“€ 수 μžˆμ–΄ μ΅œλ‹¨ κ²½λ‘œκ°€ μ •μ˜λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

음수 사이클 κ²€μΆœ 원리 πŸ•΅οΈβ€β™‚οΈ

  • 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ€ μ΅œλŒ€ V - 1번의 μ™„ν™” 과정을 톡해 μ΅œλ‹¨ 거리λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.
  • λ§Œμ•½ V번째 λ°˜λ³΅μ—μ„œ 거리가 더 쀄어든닀면, μ΄λŠ” 음수 사이클을 톡해 λ¬΄ν•œνžˆ μž‘μ€ 거리λ₯Ό λ§Œλ“€ 수 μžˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.
  • λ”°λΌμ„œ, λͺ¨λ“  간선을 μΆ”κ°€λ‘œ ν•œ 번 더 κ²€μ‚¬ν•˜μ—¬ 거리가 κ°±μ‹ λ˜λ©΄ 음수 사이클이 μ‘΄μž¬ν•œλ‹€κ³  νŒλ‹¨ν•©λ‹ˆλ‹€.

4. μ‹œκ°„ λ³΅μž‘λ„ ⏱️

  • μ‹œκ°„ λ³΅μž‘λ„: O(V * E)
    • VλŠ” μ •μ μ˜ 수, EλŠ” κ°„μ„ μ˜ μˆ˜μž…λ‹ˆλ‹€.
    • λͺ¨λ“  간선에 λŒ€ν•΄ V - 1번의 λ°˜λ³΅μ„ μˆ˜ν–‰ν•˜λ―€λ‘œ 이와 같은 μ‹œκ°„ λ³΅μž‘λ„λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

5. λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜κ³Όμ˜ 비ꡐ πŸ€”

νŠΉμ„±λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜λ²¨λ§Œ-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜
κ°€μ€‘μΉ˜ μ‘°κ±΄λΉ„μŒμˆ˜ κ°€μ€‘μΉ˜μŒμˆ˜ κ°€μ€‘μΉ˜ ν—ˆμš©
μ‹œκ°„ λ³΅μž‘λ„O(V + E log V) (μš°μ„ μˆœμœ„ 큐 μ‚¬μš© μ‹œ)O(V * E)
음수 사이클 κ²€μΆœλΆˆκ°€λŠ₯κ°€λŠ₯
μš©λ„λΉ λ₯Έ 계산이 ν•„μš”ν•  λ•Œ μ‚¬μš©μŒμˆ˜ κ°€μ€‘μΉ˜λ‚˜ 음수 사이클이 μžˆμ„ λ•Œ μ‚¬μš©

6. μˆ˜ν–‰ κ³Όμ • πŸ› οΈ

1. μ΄ˆκΈ°ν™”

  • 거리(distance)와 이전 정점(predecessor) μ΄ˆκΈ°ν™”

    distance = {vertex: float('inf') for vertex in vertices}
    predecessor = {vertex: None for vertex in vertices}
    distance[start] = 0

2. κ°„μ„  μ™„ν™” 반볡

  • V - 1번 λ°˜λ³΅ν•˜λ©° λͺ¨λ“  κ°„μ„  μ™„ν™”

    for _ in range(len(vertices) - 1):
        for edge in edges:
            u = edge.source
            v = edge.target
            w = edge.weight
            if distance[u] + w < distance[v]:
                distance[v] = distance[u] + w
                predecessor[v] = u

3. 음수 사이클 κ²€μΆœ

  • μΆ”κ°€λ‘œ ν•œ 번 더 κ°„μ„  μ™„ν™” μ‹œλ„

    for edge in edges:
        u = edge.source
        v = edge.target
        w = edge.weight
        if distance[u] + w < distance[v]:
            print("음수 사이클이 μ‘΄μž¬ν•©λ‹ˆλ‹€. ⚠️")
            return None

7. 파이썬 μ½”λ“œ κ΅¬ν˜„ 🐍

class Edge:
    def __init__(self, source, target, weight):
        self.source = source  # μ‹œμž‘ 정점
        self<.target = target  # 도착 정점
        self.weight = weight  # κ°€μ€‘μΉ˜

def bellman_ford(vertices, edges, start):
    # 거리 및 이전 정점 μ΄ˆκΈ°ν™”
    distance = {vertex: float('inf') for vertex in vertices}
    predecessor = {vertex: None for vertex in vertices}
    distance[start] = 0

    # κ°„μ„  μ™„ν™” 반볡
    for _ in range(len(vertices) - 1):
        for edge in edges:
            u = edge.source
            v = edge.target
            w = edge.weight
            if distance[u] + w < distance[v]:
                distance[v] = distance[u] + w
                predecessor[v] = u

    # 음수 사이클 κ²€μΆœ
    for edge in edges:
        u = edge.source
        v = edge.target
        w = edge.weight
        if distance[u] + w < distance[v]:
            print("음수 사이클이 μ‘΄μž¬ν•©λ‹ˆλ‹€. ⚠️")
            return None

    return distance, predecessor

# μ‚¬μš© 예제
vertices = ['A', 'B', 'C', 'D', 'E']
edges = [
    Edge('A', 'B', 6),
    Edge('A', 'C', 7),
    Edge('B', 'C', 8),
    Edge('B', 'D', 5),
    Edge('B', 'E', -4),
    Edge('C', 'D', -3),
    Edge('C', 'E', 9),
    Edge('D', 'B', -2),
    Edge('E', 'D', 7),
    Edge('E', 'A', 2)
]

start_vertex = 'A'
result = bellman_ford(vertices, edges, start_vertex)

if result:
    distances, predecessor = result
    for vertex in vertices:
        print(f"{start_vertex}μ—μ„œ {vertex}κΉŒμ§€μ˜ μ΅œλ‹¨ 거리: {distances[vertex]}")
        # 경둜 좜λ ₯
        path = []
        current_vertex = vertex
        while current_vertex is not None:
            path.insert(0, current_vertex)
            current_vertex = predecessor[current_vertex]
        print(f"경둜: {' -> '.join(path)}")
else:
    print("음수 μ‚¬μ΄ν΄λ‘œ 인해 μ΅œλ‹¨ 거리λ₯Ό 계산할 수 μ—†μŠ΅λ‹ˆλ‹€. ❌")

μ½”λ“œ μ„€λͺ… πŸ’‘

  • Edge 클래슀:
    • κ°„μ„ μ˜ μ‹œμž‘ 정점(source), 도착 정점(target), κ°€μ€‘μΉ˜(weight)λ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.
  • bellman_ford ν•¨μˆ˜:
    • μž…λ ₯: 정점 리슀트(vertices), κ°„μ„  리슀트(edges), μ‹œμž‘ 정점(start)
    • 좜λ ₯: 각 μ •μ κΉŒμ§€μ˜ μ΅œλ‹¨ 거리(distance)와 이전 정점(predecessor)
    • λ™μž‘:
      • 거리와 이전 정점을 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.
      • κ°„μ„  μ™„ν™”λ₯Ό V - 1번 λ°˜λ³΅ν•˜μ—¬ μ΅œλ‹¨ 거리λ₯Ό κ°±μ‹ ν•©λ‹ˆλ‹€.
      • 음수 사이클 κ²€μΆœμ„ μœ„ν•΄ ν•œ 번 더 κ°„μ„  μ™„ν™”λ₯Ό μ‹œλ„ν•©λ‹ˆλ‹€.
  • μ‚¬μš© 예제:
    • 정점과 간선을 μ •μ˜ν•˜κ³ , bellman_ford ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€.
    • κ²°κ³Όλ‘œλΆ€ν„° 각 μ •μ κΉŒμ§€μ˜ μ΅œλ‹¨ 거리와 경둜λ₯Ό 좜λ ₯ν•©λ‹ˆλ‹€.

μ‹€ν–‰ κ²°κ³Ό πŸ“Š

Aμ—μ„œ AκΉŒμ§€μ˜ μ΅œλ‹¨ 거리: 0
경둜: A
Aμ—μ„œ BκΉŒμ§€μ˜ μ΅œλ‹¨ 거리: 2
경둜: A -> C -> D -> B
Aμ—μ„œ CκΉŒμ§€μ˜ μ΅œλ‹¨ 거리: 7
경둜: A -> C
Aμ—μ„œ DκΉŒμ§€μ˜ μ΅œλ‹¨ 거리: 4
경둜: A -> C -> D
Aμ—μ„œ EκΉŒμ§€μ˜ μ΅œλ‹¨ 거리: -2
경둜: A -> C -> D -> B -> E

음수 사이클 μ˜ˆμ‹œ 및 κ²€μΆœ βš™οΈ

λ§Œμ•½ κ·Έλž˜ν”„μ— 음수 사이클이 μ‘΄μž¬ν•˜λ„λ‘ 간선을 μΆ”κ°€ν•œλ‹€λ©΄:

edges.append(Edge('D', 'A', -10))
  • 음수 사이클 ν˜•μ„±: Dμ—μ„œ A둜 κ°€λŠ” κ°„μ„ μ˜ κ°€μ€‘μΉ˜κ°€ -10이 λ˜μ–΄ 음수 사이클이 μƒμ„±λ©λ‹ˆλ‹€.

  • κ²€μΆœ κ²°κ³Ό:

    음수 사이클이 μ‘΄μž¬ν•©λ‹ˆλ‹€. ⚠️
    음수 μ‚¬μ΄ν΄λ‘œ 인해 μ΅œλ‹¨ 거리λ₯Ό 계산할 수 μ—†μŠ΅λ‹ˆλ‹€. ❌

8. κ²°λ‘  πŸŽ‰

벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ€ 음수 κ°€μ€‘μΉ˜κ°€ μžˆλŠ” κ·Έλž˜ν”„μ—μ„œλ„ μ•ˆμ „ν•˜κ²Œ μ΅œλ‹¨ 경둜λ₯Ό 찾을 수 있으며, 음수 μ‚¬μ΄ν΄μ˜ 쑴재 μ—¬λΆ€κΉŒμ§€ κ²€μΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜κ³Ό λΉ„κ΅ν•˜μ—¬ μ‹œκ°„ λ³΅μž‘λ„λŠ” λ†’μ§€λ§Œ, 그만큼 적용 λ²”μœ„κ°€ λ„“μŠ΅λ‹ˆλ‹€.

  • μž₯점:
    • 음수 κ°€μ€‘μΉ˜μ™€ 음수 사이클을 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€. πŸ‘
    • κ΅¬ν˜„μ΄ 비ꡐ적 κ°„λ‹¨ν•©λ‹ˆλ‹€.
  • 단점:
    • μ‹œκ°„ λ³΅μž‘λ„κ°€ O(V * E)둜, λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜λ³΄λ‹€ λŠλ¦½λ‹ˆλ‹€. 🐒
  • μ‘μš© λΆ„μ•Ό:
    • 음수 κ°€μ€‘μΉ˜κ°€ μ‘΄μž¬ν•˜λŠ” κ·Έλž˜ν”„μ˜ μ΅œλ‹¨ 경둜 계산.
    • 금육 λΆ„μ•Όμ—μ„œμ˜ 차읡 거래(arbitrage) 기회 탐지. πŸ’°
    • λ„€νŠΈμ›Œν¬μ—μ„œμ˜ 거리 벑터 λΌμš°νŒ… μ•Œκ³ λ¦¬μ¦˜.

πŸ“Œ μ°Έκ³  자료


이 ν¬μŠ€νŠΈκ°€ 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ„ μ΄ν•΄ν•˜λŠ” 데 도움이 λ˜μ…¨κΈΈ λ°”λžλ‹ˆλ‹€. 😊 μ§ˆλ¬Έμ΄λ‚˜ μΆ”κ°€ μ„€λͺ…이 ν•„μš”ν•˜μ‹œλ©΄ λŒ“κΈ€λ‘œ λ‚¨κ²¨μ£Όμ„Έμš”! πŸ“

0개의 λŒ“κΈ€