오늘도 공부한 알고리즘 정리하기,,
문제를 풀어야하는데 은근히 알고리즘 이론 공부하는게 재밌어서 정리하게 된다.

TodayPS : 최단 경로 알고리즘 (Dijkstra, Floyd-Warshall)

최단경로 (Short-Path) 알고리즘

말그래도 가장 짧은 경로를 찾는 알고리즘 ('길 찾기' 문제라고 불림)
문제의 유형은 아래 2개가 가장 대표적이다

'한 지점에서 다른 특정 지점까지의 최단 경로를 구하는 경우'
'모든 지점에서 다른 모든 지점까지의 최단경로를 모두 구해야하는 경우'

다익스트라 (Dijkstra) 알고리즘

그래프에서 여러 개의 노드가 있을 때 특정한 노드에서 출발하여 다른 노드로 가는 각각의 최단 경로를 구해주는 알고리즘이다.
-음의 간선(0보다 작은 값을 가진 간선)이 없을 때 정상적으로 동작한다
-그리디 알고리즘으로 분류 된다.
-한 단계 당 하나의 노드에 대한 최단 거리를 찾는다.

알고리즘 원리

1) 출발노드를 설정한다
2) 최단 거리 테이블을 초기화 한다 (1차원 리스트)
3) 방문하지 않은 노드 중에서 최단거리가 가장 짦은 노드를 선택한다
4) 해당 노드를 거쳐 다른 노드를 가는 비용을 계산하여 최단 거리 테이블을 갱신한다
5) 3),4)번 과정을 반복한다.

  • 다익스트라 알고리즘은 항상 1차원 리스트에 최단거리 정보를 저장한다

알고리즘 구현 방법은 2가지로 나뉜다

1) 구현하기 쉽지만 느리게 동작하는 코드 (일차원 리스트를 사용하는 방법)
2) 구현하기 까다롭지만 빠르게 동작하는 코드 (우선순위 큐를 사용하는 방법)

1. 간단한 다익스트라 알고리즘 (일차원 리스트 사용)

-O(V^2)의 시간복잡도를 갖는다. (*V는 노드의 개수)
-노드(V)의 개수가 5000개 이하 일때 시간초과 나지 않음, 10000개 이상이면 개선 된 알고리즘 사용을 고려해 볼 필요가 있다.

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)]
#방문 한 적이 있는 지 확인하는 리스트
visited = [False]*(n+1)
#최단거리 테이블을 모두 무한으로 초기화 
dist = [INF]*(n+1)

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

#방문하지 않은 노드 중에서, 가장 최단 거리가 짧은 노드의 번호 return 
def get_smallest_node():
	min_value = INF 
    index = 0 
    for i in range(1,n+1):
    	if dist[i] < min_value and not visited[i]:
        	min_value = dist[i]
            index = i
    return index
    
def dijkstra(start):
    #시작 노드에 대해서 초기화 
    dist[start] = 0
    visited[start] = True
    for j in graph[start]:
    	dist[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 = dist[now]+j[1]
            #현재 노드를 거쳐서 다른 노드로 이동하는 거리가 더 짧은 경우 
            if cost <dist[j[0]]:
            dist[j[0]] = cost

#다익스트라 알고리즘 수행 
dijkstra(start)

#모든 노드로 가기 위한 최단 거리 출력 
for i in range(n+1):
	print(dist[i]])

2.개선된 다익스트라 알고리즘 (우선순위 큐 사용)

-O(ElogV)의 시간 복잡도를 갖는다 (E는 간선의 개수, V는 노드의 개수)
-최단거리 리스트를 1차원 리스트 대신 최소 힙을 사용한다.
-현재 가장 가까운 노드를 저장하기 위한 목적으로만 우선순위 큐를 이용

** 최소힙에 대한 설명은 다른 포스트에서 하고, 간단하게 설명하자면
1) 우선순위가 가장 높은 데이터를 먼저 삭제한다.
-최소 힙에서는 우선순위가 가장 높은 데이터 == '값이 낮은 데이터' 이다.
2) 파이썬에서는 우선순위 큐 (priority queue)를 두가지로 구현 할 수 있는데, Priority Queue 혹은 heapq를 사용한다. (heapq 권장!)

profile
heeeeello

0개의 댓글