최단경로를 찾는 알고리즘 중 다익스트라는 오직 양의 가중치를 가진 그래프만을 취급한다. 또한 특정 출발위치에서 도착위치의 최단경로를 찾는 알고리즘으로, 모든 경로의 최단경로를 구하지 않는다.
그리디하게 정점을 선택하여 방문하고, 선택한 정점에서 인접 정점 중 방문되지 않은 것들에 대해 최단 경로를 구해가면서 도착지점에 도달한다.
아래 그래프에서 0번에서 출발해 6번까지 가는 최단경로를 다익스트라로 구해보자.
0 -> 1 -> 4
와 비교를 하기 위해서는 0 -> 3 -> 4
의 가중치를 알아야한다.
1 + 1 + 2
로 최단경로를 구할 수 있다.백준 1753 : 최단경로를 다익스트라로 구현해보면서 이해해보자.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
V = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
startNode = Integer.parseInt(br.readLine());
sb = new StringBuilder();
dist = new int[V+1];
adj = new List[V+1];
for (int i = 0; i < V+1; i++) {
adj[i] = new ArrayList<>();
}
Arrays.fill(dist,Integer.MAX_VALUE);
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine());
int u = Integer.parseInt(st.nextToken());
int v = Integer.parseInt(st.nextToken());
int w = Integer.parseInt(st.nextToken());
adj[u].add(new int[]{v,w});
}
우선 입력 받는 부분에서는 유향 그래프라는 점을 주의하고, 앞으로 간선의 가중치를 저장해 놓을 배열을 Integer.MAX_VALUE로 초기화 한다.
private static void dijkstra() {
PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[1] < o2[1]) return -1;
else return 1;
}
});
... next
}
다익스트라를 구현하기에 앞서서 우선순위 큐를 가중치가 낮은 정점부터 꺼내는 순으로 구현하자.
private static void dijkstra() {
prev ...
pq.add(new int[] {startNode,0});
dist[startNode] = 0;
while(!pq.isEmpty()) {
int[] curr = pq.poll();
int currNode = curr[0];
int currCost = curr[1];
if(dist[currNode] != currCost) continue;
for(int[] next : adj[currNode]) {
int nextNode = next[0];
int nextCost = next[1];
if(dist[nextNode] > dist[currNode] + nextCost) {
dist[nextNode] = dist[currNode] + nextCost;
pq.offer(new int[] {nextNode,dist[nextNode]});
}
}
}
}
시작 정점은 항상 가중치가 0이기 때문에 while문에 들어가기 앞서서 초기화 해준다. 다음 로직에서 주의깊게 봐야할 점은 두가지다.
if(dist[currNode] != currCost) continue;
: 방문했던 노드는 방문하지 않는다는 역할을 해준다. 우선순위 큐를 다시한번 되짚어 보자. 분명 가중치가 낮은것부터 꺼내지는데, 매번 다음 정점을 큐에 넣을때는 누적 가중치의 합을 넣는 다는 점을 기억하자.
즉, 특정 정점에 도착 했다는 것은 해당 정점까지의 최단 경로라는 의미이고, 따라서 가중치의 합이 변경될 일이 없으니 dist 배열 값은 최소값으로 고정된다.
dist[nextNode] > dist[currNode] + nextCost)
: 위에서 언급했다시피, 이미 최단 경로가 구해진 상태라면 더이상 dist 배열이 초기화 되지 않는다.
다익스트라의 시간복잡도는 이진힙, 즉 우선순위 큐를 이용한다면 O(ElogV)의 시간복잡도를 가진다.