728x90
최단 경로는?
- 두 노드를 잇는 가장 짧은 경로를 찾는 문제
- 가중치 그래프(Weighted Graph)에서 간선(Edge)의 가중치 합이 최소가 되도록 하는 경로를 찾는 것이 목적
최단 경로 문제 종류
1. 단일 출발 및 단일 도착(single-source and single-destination shortest path problem)최단 경로 문제
- 그래프 내의 특정 노드 u에서 출발, 또다른 특정 노드 v에 도착하는 가장 짧은 경로를 찾는 문제
2. 단일 출발(single-source shortest path problem) 최단 경로 문제
- 그래프 내의 특정 노드 u와 그래프 내 다른 모든 노드 각각의 가장 짧은 경로를 찾는 문제
3. 전체 쌍(all-pair)최단경로 : 그래프 내의 모든 노드 쌍(u, v)에 대한 최단 경로를 찾는 문제
최단 경로 알고리즘 - 다익스트라 알고리즘
- 다익스트라 알고리즘은 단일 출발에 해당
- 하나의 정점에서 다른 모든 정점 간의 각각 가장 짧은 거리를 구함
다익스트라 알고리즘 로직
- 첫 정점을 기준으로 연결되어 있는 정점들을 추가해 가며 최단 거리를 갱신하는 기법
- 다익스트라 알고리즘은 너비우선탐색(BFS)와 유사함
- 첫 정점부터 각 노드간의 거리를 저장하는 배열을 만든 후 첫 정점의 인접 노드 간의 거리부터 먼저
계산하면서 첫 정점부터 해당 노드간의 가장 짧은 거리를 해당 배열에 업데이트
- 우선순위 큐를 활용한 다익스트라 알고리즘
- 우선순위 큐는 MinHeap방식을 활용해서 현재 가장 짧은 거리를 가진 노드 정보를 먼저 꺼내게 됨
1) 첫 정점을 기준으로 배열을 선언하여 첫 정점에서 각 정점까지의 거리를 저장
- 초기에는 첫 정점의 거리는 0 나머지는 무한대로 저장함(inf 라고 표현함)
- 우선순위 큐에 (첫 정점, 거리 0)만 먼저 넣음
2) 우선순위 큐에서 노드를 꺼냄
- 처음에는 첫 정점만 저장되어 있으므로 첫 정점이 꺼내짐
- 첫 정점에 인접한 노드를 각각에 대해 첫 정점에서 각 노드로 가는 거리와 현재 배열에 저장되어 있는
첫 정점에서 각 정점까지의 거리를 비교함
- 배열에 저장되어 있는 거리보다 첫 정점에서 해당 노드로 가는 거리가 더 짧을 경우 배열에 해당 노드의
거리를 업데이트함
- 배열에 해당 노드의 거리가 업데이트 된 경우 우선순위 큐에 넣음
- 결과적으로 너비 우선 탐색 방식과 유사하게 첫 정점에 인접한 노드들을 순차적으로 방문하게 됨
- 만약 배열에 기록된 현재까지 발견된 가장 짧은 거리보다 더 긴 거리를 가진 노드의 경우에는 해당 노드와
인접한 노드간의 거리 계산을 하지 않음
3) 2번의 과정을 우선순위 큐에 꺼낼 노드가 없을 때까지 반복한다.
다익스트라 알고리즘(우선순위 큐 활용) 예
1단계 : 초기화
- 첫 정점을 기준으로 배열을 선언하여 첫 정점에서 각 정점까지의 거리 저장
- 초기에는 첫 정점의 거리는 0 나머지는 무한대로 저장(inf라고 표현)
- 우선순위 큐에(첫 정점, 거리0)만 먼저 넣음
2단계 : 우선선위 큐에서 추출한 (A, 0) [노드, 첫 노드와의 거리]를 기반으로 인접한 노드와의 거리 계산
- 우선순위 큐에서 노드를 꺼냄
- 처음에는 첫 정점만 저장되어 있으므로 첫 정점이 꺼내짐
- 첫 정점에 인접한 노드를 각각에 대해 첫 정점에서 각 노드로 가는 거리와 현재 배열에 저장되어 있는
첫 정점에서 각 정점까지의 거리를 비교함
- 배열에 저장되어 있는 거리보다 첫 정점에서 해당 노드로 가는 거리가 더 짧을 경우 배열에 해당 노드의
거리를 업데이트함
- 배열에 해당 노드의 거리가 업데이트된 경우 우선순위 큐에 넣음
- 결과적으로 너비 우선 탐색 방식과 유사하게 첫 정점에 인접한 노드들을 순차적으로 방문하게 됨
- 만약 배열에 기록된 현재까지 발견된 가장 짧은 거리보다 더 긴 거리를 가진 노드의 경우에는 해당
노드와 인접한 노드간의 거리 계산을 하지 않음
==>1단계에서 첫 정점이외에 모두 inf였으므로 첫 정점에 인접한 노드들은 모두 우선순위 큐에 들어가고
첫 정점과 인접한 노드간의 거리가 배열에 업데이트됨
3단계 : 우선순위 큐에서(C, 1) [노드, 첫 노드와의 거리]를 기반으로 인접한 노드와의 거리 계산
- 우선순위 큐가 MinHeap(최소합) 방식이므로 2단계에서 넣어진 (C, 1), (D, 2), (B, 8) 중 (C, 1)이 먼저 추출(pop)
- 2단계 표에서 보듯이 1단계까지의 A - B 최단 거리는 8임
- A - C까지의 거리는 1, C에 인접한 B, D에서 C - B는 5, 즉 A - C - B는 1 + 5 = 6 이므로
A - B 최단거리 8보다 더 작은 거리를 발견하여 배열에 업데이트 B, 6 값이 우선순위 큐에 넣어짐
- C - D의 거리는 2, 즉 A - C - D는 1 + 2 = 3이므로 A - D의 현재 최단 거리인 2보다 긴 거리, D의 거리는
업데이트 되지 않음
4단계 : 우선순위 큐에서(D, 2) [노드, 첫 노드와의 거리]를 기반으로 인접한 노드와의 거리 계산
- 지금까지 접근하지 못했던 E와 F의 거리가 계산됨
- A - D까지의 거리인 2에 D - E가 3이므로 이를 더해서 E, 5
- A - D까지의 거리인 2에 D - F가 5이므로 이를 더해서 F, 7
5단계 : 우선순위 큐에서(E, 50) [노드, 첫 노드와의 거리]를 기반으로 인접한 노드와의 거리 계산
- A - E거리가 5인 상태에서 E에 인접한 F를 가는 거리는 1, 즉 A - E - F는 5 + 1 = 6 현재 배열에 A - F
최단거리가 7로 기록되어 있으므로 F, 6으로 업데이트
- 우선순위 큐에 F, 6 추가
6단계 : 우선순위 큐에서 (B, 6), (F, 6)를 순차적으로 추출해 각 노드 기바으로 인접한 노드와의 거리 계산
- 예제의 방향 그래프에서 B노드는 다른 노드로 가는 루트가 없음
- F 노드는 A노드로 가는 루트가 있으나 현재 A - A가 0인 반면에 A - F - A는 6 + 5 = 11 즉 더 긴 거리이므로
업데이트되지 않음
6단계 : 우선순위 큐에서 (F, 7), (B, 8)를 순차적으로 추출해 각 노드 기반으로 인접한 노드와의 거리 계산
- A - F로 가는 하나의 루트의 거리가 7인 상황이나 배열에서 이미 A - F로 가는 현재의 최단거리가 6인
루트의 값이 있는 상황이므로 더 긴거리인 F, 7루트 기반 인접 노드까지의 거리는 계산할 필요가 없음
- B, 8도 현재 A - B거리가 6이므로 인접 노드 거리 계산이 필요 없음
우선순위 큐 사용 장점
- 지금까지 발견된 가장 짧은 거리의 노드에 대해서 먼저 계산
- 더 긴 거리로 계산된 루트에 대해서는 계산을 스킵할 수 있음
다익스트라 알고리즘 파이썬 구현
import heapq
queue = []
heapq.heappush(queue, [2, 'A'])
heapq.heappush(queue, [5, 'B'])
heapq.heappush(queue, [1, 'C'])
heapq.heappush(queue, [7, 'D'])
print (queue)
for index in range(len(queue)):
print (heapq.heappop(queue))
"""
출력결과
[[1, 'C'], [5, 'B'], [2, 'A'], [7, 'D']]
[1, 'C']
[2, 'A']
[5, 'B']
[7, 'D']
"""
#다익스트라 알고리즘 - 탐색할 그래프의 시작 정점과 다른 정점들간의 최단 거리 구하기
mygraph = {
'A': {'B': 8, 'C': 1, 'D': 2}.
'B': {},
'C': {'B': 5, 'D': 2},
'D': {'E': 3, 'F': 5},
'E': {'F': 1},
'F': {'A': 5}
}
import heapq
def dijkstra(graph, start):
distance = {node: float('inf') for node in graph}
distance[start] = 0
queue = []
heapq.heappush(queue, [disatance[start], start])
while queue:
current_distance, current_node = heapq.heappop(queue)
if distance[current_node] < current_distance:
continue
for adjacent, weight in graph[current_node].items():
distance = current_distance + weight
if distance < distances[adjacent]:
distances[adjacent] = distance
heapq.heappush(queue, [distance, adjacent])
return distances
dijkstra(mygraph, 'A')
#출력결과 {'A': 0, 'B': 6, 'C': 1, 'D': 2, 'E': 5, 'F': 6}
'IT개발 > 알고리즘, 우리 친해지자!' 카테고리의 다른 글
알고리즘 : 최소 신장트리1-2 (0) | 2021.10.09 |
---|---|
알고리즘 : 최소 신장 트리1 (0) | 2021.10.02 |
알고리즘 : 탐욕 알고리즘 (0) | 2021.09.27 |
알고리즘 : 깊이 우선 탐색(Depth-First Search) (0) | 2021.09.23 |
알고리즘 : 너비 우선 탐색(Breadth-First Search) (0) | 2021.09.21 |