๐Ÿ’ป [์ฝ”ํ…Œ06] 11์žฅ ๊ทธ๋ž˜ํ”„

๊น€๋ฏธ์—ฐยท2024๋…„ 2์›” 25์ผ
0

11์žฅ. ๊ทธ๋ž˜ํ”„

11-1. ๊ทธ๋ž˜ํ”„์˜ ๊ฐœ๋…

  • ๋…ธ๋“œ์™€ ๊ฐ„์„ ์„ ์ด์šฉํ•œ ๋น„์„ ํ˜• ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ
  • ๋ณดํ†ต ๋ฐ์ดํ„ฐ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š”๋ฐ ์‚ฌ์šฉ
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋…ธ๋“œ๋กœ, ๋…ธ๋“œ ๊ฐ„์˜ ๊ด€๊ณ„๋‚˜ ํ๋ฆ„์„ ๊ฐ„์„ ์œผ๋กœ ํ‘œํ˜„
  • ๊ฐ„์„ ์€ ๋ฐฉํ–ฅ์ด ์žˆ๋Š” ๊ฒฝ์šฐ, ์—†๋Š” ๊ฒฝ์šฐ ๋ชจ๋‘ ๊ฐ€๋Šฅ
  • ๊ด€๊ณ„๋‚˜ ํ๋ฆ„์—์„œ ์ •๋„๋ฅผ ํ‘œํ˜„ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋ฉด ๊ฐ€์ค‘์น˜ ์ถ”๊ฐ€ํ•˜์—ฌ ํ‘œํ˜„

1) ๊ทธ๋ž˜ํ”„์˜ ํŠน์ง•๊ณผ ์ข…๋ฅ˜

  • ํ๋ฆ„์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉํ–ฅ์„ฑ(๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„, ๋ฌด๋ฐฉํ–ฅ ๊ทธ๋ž˜ํ”„)
  • ํ๋ฆ„์˜ ์ •๋„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฐ€์ค‘์น˜(๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„)
  • ์‹œ์ž‘๊ณผ ๋์˜ ์—ฐ๊ฒฐ ์—ฌ๋ถ€๋ฅผ ๋ณด๋Š” ์ˆœํ™˜(์ˆœํ™˜ ๊ทธ๋ž˜ํ”„, ๋น„์ˆœํ™˜ ๊ทธ๋ž˜ํ”„)

2) ๊ทธ๋ž˜ํ”„ ๊ตฌํ˜„

  • ์ธ์ ‘ ํ–‰๋ ฌ์„ ํ†ตํ•œ ๊ทธ๋ž˜ํ”„ ๊ตฌํ˜„
    • ์ธ์ ‘ ํ–‰๋ ฌ์€ ๋ฐฐ์—ด์„ ํ™œ์šฉํ•˜์—ฌ ๊ตฌํ˜„
    • ๋…ธ๋“œ : ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค
    • ๊ฐ€์ค‘์น˜ : ๋ฐฐ์—ด์˜ ๊ฐ’
    • ์ถœ๋ฐœ ๋…ธ๋“œ : ์ธ๋ฑ์Šค์˜ ์„ธ๋กœ ๋ฐฉํ–ฅ
    • ๋„์ฐฉ ๋…ธ๋“œ : ์ธ๋ฑ์Šค์˜ ๊ฐ€๋กœ ๋ฐฉํ–ฅ
  • ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋ฅผ ํ†ตํ•œ ๊ทธ๋ž˜ํ”„ ๊ตฌํ˜„

11-2. ๊ทธ๋ž˜ํ”„ ํƒ์ƒ‰

1) ๊นŠ์ด์šฐ์„  ํƒ์ƒ‰ ์ˆœํšŒ

from collections import defaultdict

def solution(graph, start):
  # โถ ๊ทธ๋ž˜ํ”„๋ฅผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜
  adj_list = defaultdict(list)
  for u, v in graph:
    adj_list[u].append(v)

  # โท DFS ํƒ์ƒ‰ ํ•จ์ˆ˜
  def dfs(node, visited, result):
    visited.add(node)  # โธ ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋“ค์˜ ์ง‘ํ•ฉ์— ์ถ”๊ฐ€
    result.append(node)  # โน ํ˜„์žฌ ๋…ธ๋“œ๋ฅผ ๊ฒฐ๊ณผ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
    for neighbor in adj_list.get(node, []):  # โบ ํ˜„์žฌ ๋…ธ๋“œ์™€ ์ธ์ ‘ํ•œ ๋…ธ๋“œ์ˆœํšŒ
      if neighbor not in visited:  # โป ์•„์ง ๋ฐฉ๋ฌธํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ๋ผ๋ฉด
        dfs(neighbor, visited, result)

  # DFS๋ฅผ ์ˆœํšŒํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
  visited = set()
  result = []
  dfs(start, visited, result)  # โผ ์‹œ์ž‘ ๋…ธ๋“œ์—์„œ ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰ ์‹œ์ž‘
  return result  # โฝ DFS ํƒ์ƒ‰ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜

# TEST ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. ์ฃผ์„์„ ํ’€๊ณ  ์‹คํ–‰์‹œ์ผœ๋ณด์„ธ์š”
# print(solution([['A', 'B'], ['B', 'C'], ['C', 'D'], ['D', 'E']], 'A')) # ๋ฐ˜ํ™˜๊ฐ’ : ['A', 'B', 'C', 'D', 'E']
# print(solution([['A', 'B'], ['A', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'F'], ['E', 'F']], 'A')) # ๋ฐ˜ํ™˜๊ฐ’ : ['A', 'B', 'D', 'E', 'F', 'C']

2) ๋„ˆ๋น„์šฐ์„  ํƒ์ƒ‰ ์ˆœํšŒ

from collections import defaultdict, deque

def solution(graph, start):
  # ๊ทธ๋ž˜ํ”„๋ฅผ ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋กœ ๋ณ€ํ™˜
  adj_list = defaultdict(list)
  for u, v in graph:
    adj_list[u].append(v)
    
  # BFS ํƒ์ƒ‰ ํ•จ์ˆ˜
  def bfs(start):
    visited = set()  # โถ ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ๋ฅผ ์ €์žฅํ•  ์…‹
    
    # โท ํƒ์ƒ‰์‹œ ๋งจ ์ฒ˜์Œ ๋ฐฉ๋ฌธํ•  ๋…ธ๋“œ ํ‘ธ์‹œ ํ•˜๊ณ  ๋ฐฉ๋ฌธ์ฒ˜๋ฆฌ
    queue = deque([start])  
    visited.add(start)  
    result.append(start)  
    
    # โธ ํ๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š์€ ๋™์•ˆ ๋ฐ˜๋ณต
    while queue:  
      node = queue.popleft()  # โน ํ์— ์žˆ๋Š” ์›์†Œ ์ค‘ ๊ฐ€์žฅ ๋จผ์ € ํ‘ธ์‹œ๋œ ์›์†Œ ํŒ
      for neighbor in adj_list.get(node, []):  #โบ  ์ธ์ ‘ํ•œ ์ด์›ƒ ๋…ธ๋“œ๋“ค์— ๋Œ€ํ•ด์„œ
        if neighbor not in visited:  # โป ๋ฐฉ๋ฌธ๋˜์ง€ ์•Š์€ ์ด์›ƒ ๋…ธ๋“œ์ธ ๊ฒฝ์šฐ
            # โผ ์ด์›ƒ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธ ์ฒ˜๋ฆฌํ•จ
            queue.append(neighbor)
            visited.add(neighbor)  
            result.append(neighbor)

  result = []
  bfs(start)  # โฝ ์‹œ์ž‘ ๋…ธ๋“œ๋ถ€ํ„ฐ BFS ํƒ์ƒ‰ ์ˆ˜ํ–‰
  return result

# TEST ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. ์ฃผ์„์„ ํ’€๊ณ  ์‹คํ–‰์‹œ์ผœ๋ณด์„ธ์š”
# print(solution([(1, 2), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7), (4, 8), (5, 8), (6, 9), (7, 9)],1)) # ๋ฐ˜ํ™˜๊ฐ’ :[1, 2, 3, 4, 5, 6, 7, 8, 9]
# print(solution([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)],1)) # ๋ฐ˜ํ™˜๊ฐ’ : [1, 2, 3, 4, 5, 0]
 

3) ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

import heapq

def solution(graph, start):
  distances = {node: float("inf") for node in graph}  # โถ ๋ชจ๋“  ๋…ธ๋“œ์˜ ๊ฑฐ๋ฆฌ ๊ฐ’์„ ๋ฌดํ•œ๋Œ€๋กœ ์ดˆ๊ธฐํ™”
  distances[start] = 0  # โท ์‹œ์ž‘ ๋…ธ๋“œ์˜ ๊ฑฐ๋ฆฌ ๊ฐ’์€ 0์œผ๋กœ ์ดˆ๊ธฐํ™”
  queue = []
  heapq.heappush(queue, [distances[start], start])  # โธ ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ํ์— ์‚ฝ์ž…
  paths = {start: [start]}  # โน ์‹œ์ž‘ ๋…ธ๋“œ์˜ ๊ฒฝ๋กœ๋ฅผ ์ดˆ๊ธฐํ™”

  while queue:
    # โบ ํ˜„์žฌ ๊ฐ€์žฅ ๊ฑฐ๋ฆฌ ๊ฐ’์ด ์ž‘์€ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜ด
    current_distance, current_node = heapq.heappop(queue)
    # โป ๋งŒ์•ฝ ํ˜„์žฌ ๋…ธ๋“œ์˜ ๊ฑฐ๋ฆฌ ๊ฐ’์ด ํ์—์„œ ๊ฐ€์ ธ์˜จ ๊ฑฐ๋ฆฌ ๊ฐ’๋ณด๋‹ค ํฌ๋ฉด, ํ•ด๋‹น ๋…ธ๋“œ๋Š” ์ด๋ฏธ ์ฒ˜๋ฆฌํ•œ ๊ฒƒ์ด๋ฏ€๋กœ ๋ฌด์‹œ
    if distances[current_node] < current_distance:
      continue

    # โผ ํ˜„์žฌ ๋…ธ๋“œ์™€ ์ธ์ ‘ํ•œ ๋…ธ๋“œ๋“ค์˜ ๊ฑฐ๋ฆฌ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜์—ฌ ์—…๋ฐ์ดํŠธ
    for adjacent_node, weight in graph[current_node].items():
      distance = current_distance + weight
      # โฝ ํ˜„์žฌ ๊ณ„์‚ฐํ•œ ๊ฑฐ๋ฆฌ ๊ฐ’์ด ๊ธฐ์กด ๊ฑฐ๋ฆฌ ๊ฐ’๋ณด๋‹ค ์ž‘์œผ๋ฉด ์ตœ์†Œ ๋น„์šฉ ๋ฐ ์ตœ๋‹จ ๊ฒฝ๋กœ ์—…๋ฐ์ดํŠธ
      if distance < distances[adjacent_node]:
        distances[adjacent_node] = distance  # ์ตœ์†Œ ๋น„์šฉ ์—…๋ฐ์ดํŠธ
        paths[adjacent_node] = paths[current_node] + [adjacent_node] # ์ตœ๋‹จ ๊ฒฝ๋กœ ์—…๋ฐ์ดํŠธ

        # โž’ ์ตœ์†Œ ๊ฒฝ๋กœ๊ฐ€ ๊ฐฑ์‹ ๋œ ๋…ธ๋“œ๋ฅผ ๋น„์šฉ๊ณผ ํ•จ๊ป˜ ํ์— ํ‘ธ์‹œ
        heapq.heappush(queue, [distance, adjacent_node])

  # โž“ paths ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ๋…ธ๋“œ ๋ฒˆํ˜ธ์— ๋”ฐ๋ผ ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌํ•˜์—ฌ ๋ฐ˜ํ™˜
  sorted_paths = {node: paths[node] for node in sorted(paths)}

  return [distances, sorted_paths]


# TEST ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. ์ฃผ์„์„ ํ’€๊ณ  ์‹คํ–‰์‹œ์ผœ๋ณด์„ธ์š”
# print(solution({ 'A': {'B': 9, 'C': 3}, 'B': {'A': 5}, 'C': {'B': 1} },'A')) # ๋ฐ˜ํ™˜๊ฐ’ :[{'A': 0, 'B': 4, 'C': 3}, {'A': ['A'], 'B': ['A', 'C', 'B'], 'C': ['A', 'C']}]
# print(solution({'A': {'B': 1},'B': {'C': 5},'C': {'D': 1},'D': { } }, 'A')) # ๋ฐ˜ํ™˜๊ฐ’ :[{'A': 0, 'B': 1, 'C': 6, 'D': 7}, {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'B', 'C'], 'D': ['A', 'B', 'C', 'D']}]

4) ๋ฒจ๋งŒ-ํฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜

def solution(graph, source):
  # โžŠ ๊ทธ๋ž˜ํ”„์˜ ๋…ธ๋“œ ์ˆ˜
  num_vertices = len(graph)

  # โž‹ ๊ฑฐ๋ฆฌ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
  distance = [float("inf")] * num_vertices
  distance[source] = 0

  # โžŒ ์ง์ „ ๊ฒฝ๋กœ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
  predecessor = [None] * num_vertices

  # โž ๊ฐ„์„  ์ˆ˜ ๋งŒํผ ๋ฐ˜๋ณตํ•˜์—ฌ ์ตœ๋‹จ ๊ฒฝ๋กœ ๊ฐฑ์‹ 
  for temp in range(num_vertices - 1):
    for u in range(num_vertices):
      for v, weight in graph[u]:
        # โžŽ ํ˜„์žฌ ๋…ธ๋“œ u๋ฅผ ๊ฑฐ์ณ์„œ ๋…ธ๋“œ v๋กœ ๊ฐ€๋Š” ๊ฒฝ๋กœ์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ๊ธฐ์กด์— ์ €์žฅ๋œ ๋…ธ๋“œ v๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ๋ณด๋‹ค ์งง์€ ๊ฒฝ์šฐ
        if distance[u] + weight < distance[v]:
          # โž ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•ด์ค๋‹ˆ๋‹ค.
          distance[v] = distance[u] + weight
          # โž ์ง์ „ ๊ฒฝ๋กœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
          predecessor[v] = u

  # โž‘ ์Œ์˜ ๊ฐ€์ค‘์น˜ ์ˆœํšŒ ์ฒดํฌ
  for u in range(num_vertices):
    for v, weight in graph[u]:
      # โž’ ํ˜„์žฌ ๋…ธ๋“œ u๋ฅผ ๊ฑฐ์ณ์„œ ๋…ธ๋“œ v๋กœ ๊ฐ€๋Š” ๊ฒฝ๋กœ์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ๊ธฐ์กด์— ์ €์žฅ๋œ ๋…ธ๋“œ v๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ๋ณด๋‹ค ์งง์€ ๊ฒฝ์šฐ
      if distance[u] + weight < distance[v]:
        # โฟ ์Œ์˜ ๊ฐ€์ค‘์น˜ ์ˆœํšŒ๊ฐ€ ๋ฐœ๊ฒฌ๋˜์—ˆ์œผ๋ฏ€๋กœ [-1]์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
        return [-1]
  return [distance, predecessor]

# TEST ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. ์ฃผ์„์„ ํ’€๊ณ  ์‹คํ–‰์‹œ์ผœ๋ณด์„ธ์š”
# print(solution([[(1, 4), (2, 3), (4, -6 )], [(3, 5)], [(1, 2)], [(0, 7), (2, 4)],[(2, 2)]],0)) #๋ฐ˜ํ™˜๊ฐ‘ : [[0, -2, -4, 3, -6], [None, 2, 4, 1, 0]]
# print(solution([[(1, 5), (2, -1)], [(2, 2)], [(3, -2)], [(0, 2), (1, 6)]],0)) # ๋ฐ˜ํ™˜๊ฐ’ : [-1]

11-3. ํ•ฉ๊ฒฉ์ž๊ฐ€ ๋˜๋Š” ๋ชจ์˜ ํ…Œ์ŠคํŠธ

๋ฌธ์ œ42_๊ฒŒ์ž„ ๋งต ์ตœ๋‹จ ๊ฑฐ๋ฆฌ
๋ฌธ์ œ43_๋„คํŠธ์›Œํฌ
๋ฌธ์ œ44_๋ฐฐ๋‹ฌ

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด