V, E = map(int, input().split()) K = int(input()) graph= [[] for _ inrange(V+1)] for _ inrange(E): u, v, w= map(int, input().split()) graph[u].append((v,w))
distance = [INF]*(V+1) visited = [False]*(V+1)
defget_smallest_node(): min_value = INF index = 0 for i inrange(1, V+1): ifnot visited[i] and distance[i] < min_value: index = i min_value = distance[i] return index
defdijkstra(): visited[K] = True distance[K] = 0 for (i,v) in graph[K]: distance[i] = v for _ inrange(V-1): i = get_smallest_node() visited[i] = True for (j,v) in graph[i]: if distance[j] > distance[i] + v: distance[j] = distance[i]+ v
dijkstra()
for i inrange(1, V+1): if distance[i] == INF: print('INF') else: print(distance[i])
시간복잡도는 O(V^2)이다. 왜냐하면 V개의 모든 노드에 대해 3)과정을 거치며 V번의 비교를 하게 되기 때문.
우선순위 큐(최소 힙)을 이용하는 Dijkstra Algorithm
이 과정에서 우선순위 큐(최소 힙)을 이용한다면, 복잡도를 줄일 수 있다. 아래 코드는 BOJ 1753 최단경로의 답이기도 하다.
V, E = map(int, input().split()) K = int(input()) graph= [[] for _ inrange(V+1)] for _ inrange(E): u, v, w= map(int, input().split()) graph[u].append((v,w))
distance = [INF]*(V+1)
defdijkstra(): q = [] distance[K] = 0 heapq.heappush(q, (0, K)) while q: dist, node = heapq.heappop(q) if distance[node] < dist: continue for (j,v) in graph[node]: cost = distance[node]+ v if distance[j] > cost: distance[j] = cost heapq.heappush(q, (cost, j))
dijkstra()
for i inrange(1, V+1): if distance[i] == INF: print('INF') else: print(distance[i])
이 과정에서는 최단거리 노드를 찾는 데에 O(VlogV)가 필요하고(V개의 노드에 대해 힙에서 추출하는 시간 logV, 각 노드가 인접한 노드를 갱신할 때 (visited를 체크하지 않으므로) 모든 간선을 확인하는 것과 같으며 갱신될 때 logV가 필요하므로 O(ElogV)가 필요하다. 결과적으론 O((E+V)logV)가 필요한 셈.
이 부분에서 헷갈린게 있었는데, 최악의 경우 E는 V^2 스케일일 때 복잡도를 비교하면 전자가 더 빠르다. 즉 그래프가 sparse할 때만 효율적이다.