최단경로 : 다익스트라 - 이론정리 (미완)

Yona·2022년 1월 2일
0

🌻 algorithm

목록 보기
10/18

다익스트라

  • 사용 : 특정노드에서 다른 모든 노드로의 최단 경로를 구함
  • 전제조건 : weight가 음수일 수 없음
  • 시간복잡도 :

다익스트라

동작원리
1. 출발노드 설정
2. 최단거리 테이블 초기화
3. 방문하지 않은 노드 중 최단거리가 가장 짧은 노드 선택
4. 해당 노드를 거쳐 다른 노드로 가는 비용 계산하여 최단 거리 테이블 갱신
5. 3번과 4번 반복

자다가도 바로 작성할 수 있을정도로 코드에 숙달되어있어야한다

동작 예시

출발 노드가 1일때, 다른 모든 노드로의 최단거리를 계산

노드번호123456결과
거리0INFINFINFINFINF1선택
-251INFINF4선택
-24-2INF2선택
--3-245선택
--3--43선택
----46선택

= 1번 노드에서 출발했을때
2,3,4,5,6번 노드까지의 최단경로는 각각
2,3,1,2,4 라는 뜻이다!

간단한 다익스트라 알고리즘 O(V^2)

import sys
input = sys.stdin.readline
INF = int(1e9) #무한으로 10억 설정

# 노드 갯수, 간선 갯수 입력받기
n, m = map(int, input().split())
# 시작 노드 번호 입력받기
start = int(input())
# 각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트 만들기
graph = [[] for i in range(n+1)]
# 방문한 적이 있는지 체크하는 목적의 리스트 만들기
visited = [False] * (n+1)
# 최단 거리 테이블을 모두 무한으로 초기화
distance = [INF] * (n+1)

# 모든 간선 정보를 입력받기
for _ in range (m) :
	a, b, c = map(int, input().split()) #a번 노드에서 b번 노드로 가는 비용이 c라는 의미
	graph[a].append((b,c))

# 방문하지 않은 노드 중에서, 가장 최단거리가 짧은 노드의 번호를 반환
def get_smallest_node() :
	min_value = INF
	index = 0 # 가장 최단거리가 짧은 노드의 인덱스
	for i in range(1, n+1) :
		if distance[i] < min_value and not visited[i] :
			min_value = distance[i]
			index = i
	return index

def dijkstra(start) :
	#시작노드에 대해 초기화
	distance[start] = 0
	visited[start] = True
	for j in graph[start] :#시작노드와 연결되어있다면, 거리를 기록한다
		distance[j[0]] = j[1]
	# 시작노드를 제외한 전체 n-1개의 노드에 대해 반복
	for i in range(n-1) :
		#현재 최단 거리가 가장 짧은 노드를 꺼내서, 방문 처리
		now = get_smallest_node()
		visited[now] = True
		# 현재 노드와 연결된 다른 노드를 혹인
		for j in graph[now] :
			cost = distance[now] + j[1]
			if cost < distance[j[0]] :
				distance[j[0]] = cost

dijkstra(start)

# 모든 노드로 가기 위한 최단거리 출력
for i in range(1, n+1) :
	# 도달할 수 없는 경우, 무한(Infinity)라고 출력
	if distance[i] == INF :
		print("INFINITY")
	else :
		print(distance[i])

시간복잡도 : O(V2)O(V^2)

  • O(V)번에 걸쳐서 최단거리가 가장 짧은 노드를 매번 선형 탐색 X O(V)번에 걸쳐서 현재 노드와 연결된 노드를 매번 일일이 확인

개선된 다익스트라

시간복잡도 : O(ElogV)O(ElogV)
현재 가장 가까운 노드를 O(V)만큼 연산해서 찾는게 아니라,
우선순위 큐를 이용하여 O(logN)(N:우선순위큐안의데이터갯수)O(logN)_{(N:우선순위 큐 안의 데이터 갯수)} 만큼 빠르게 꺼내서 찾는다.

우선순위큐
우선순위가 높은데이터를 가장 먼저 삭제. 삭제/삽입의 시간복잡도는 O(logN)(N:우선순위큐안의데이터갯수)O(logN)_{(N:우선순위 큐 안의 데이터 갯수)}

코드

import heapq
import sys
input = sys.stdin.readline
INF = int(1e9)

# 노드의 갯수, 간선의 갯수 입력받기
n, m = map(int, input().split())
# 시작 노드 번호 입력받기
start = int(input())
# 각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트를 만들기
graph = [[] for i in range(n+1)]
# 최단거리 테이블을 모두 무한으로 초기화
distance = [INF] * (n+1)

# 모든 간선 정보를 입력받기
for _ in range :
	a,b,c = map(int, input().split()) # a번 노드에서 b번 노드에서 가는 비용이 c라는 의미
	graph[a].append((b,c))

def dijkstra(start) :
	q = []
	# 시작 노드로 가기 위한 최단경로는 0으로 설정하며, 큐에 삽입
	heapq.heappush(q, (0, start))
	distance[start] = 0
	while q : # 큐가 비어있지 않다면
		# 가장 최단 거리가 짧은 노드에 대한 정보 꺼내기
		dist, now = heapq.headpop(q)
		# 현재 노드가 이미 처리된 적이 있는 노드라면 무시
		if distance[now] < dist :
			continue
		# 현재 노드와 연결된 다른 인접한 노드들을 확인
		for i in graph[now] :
			cost = dist + i[1]
			# 현재 노드를 거쳐서, 다른 노드로 이동하는 거리가 더 짧은 경우
			if cost < distance[i[0]] :
				distance[i[0]] = cost
				heapq.heappush(q, (cost, i[0]))

dijkstra(start)

# 모든 노드로 가기 위한 최단거리 출력
for i in range(1, n+1) :
	# 도달할 수 없는 경우, 무한(Infinity)라고 출력
	if distance[i] == INF :
		print("INFINITY")
	else :
		print(distance[i])

시간복잡도 상세

O(ElogV)O(ElogV)에서

~ 책 250P 다시 정리하기 ~

profile
Sometimes you win, sometimes you learn 🏃‍♀️

0개의 댓글