최단 경로 알고리즘은 가장 짧은 경로를 찾는 알고리즘을 의미한다.
특정한 노드에서 출발하여 다른 모든 노드로 가는 최단 경로를 계산합니다.
단일 시작점 최단 경로 문제에 적합합니다.
음의 간선이 없을 때
정상적으로 동작한다.그리디 알고리즘
으로 분류된다.플로이드 워샬 알고리즘은 뭘까?
출발 노드를 설정한다.
최단 거리 테이블을 초기화한다.
방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드를 선택한다.
해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블을 갱신한다.
위 과정에서 3번과 4번을 반복한다.
그리디 알고리즘
매 상황에서 방문하지 않은 가장 비용이 적은 노드를 선택해 임의의 과정을 반복한다.
단계를 거치며 한번 처리된 노드의 최단 거리는 고정되어 더 이상 바뀌지 않는다.
한 단계당 하나의 노드에 대한 최단 거리를 확실히 찾는 것으로 이해할 수 있다.
import java.util.*;
class Node {
private int index;
private int distance;
public Node(int index, int distance) {
this.index = index;
this.distance = distance;
}
public int getIndex() {
return this.index;
}
public int getDistance() {
return this.distance;
}
}
public class Main {
public static final int INF = (int) 1e9;
public static int n, m, start;
public static ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();
public static boolean[] visited = new boolean[100001];
public static int[] d = new int[100001];
public static int getSmallestNode() {
int min_value = INF;
int index = 0;
for (int i = 1; i <= n; i++) {
if (d[i] < min_value && !visited[i]) {
min_value = d[i];
index = i;
}
}
return index;
}
public static void dijkstra(int start) {
d[start] = 0;
visited[start] = true;
for (int j = 0; j < graph.get(start).size(); j++) {
d[graph.get(start).get(j).getIndex()] = graph.get(start).get(j).getDistance();
}
for (int i = 0; i < n - 1; i++) {
int now = getSmallestNode();
visited[now] = true;
for (int j = 0; j < graph.get(now).size(); j++) {
int cost = d[now] + graph.get(now).get(j).getDistance();
if (cost < d[graph.get(now).get(j).getIndex()]) {
d[graph.get(now).get(j).getIndex()] = cost;
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
start = sc.nextInt();
for (int i = 0; i <= n; i++) {
graph.add(new ArrayList<Node>());
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
graph.get(a).add(new Node(b, c));
}
Arrays.fill(d, INF);
dijkstra(start);
for (int i = 1; i <= n; i++) {
if (d[i] == INF) {
System.out.println("INFINITY");
}
else {
System.out.println(d[i]);
}
}
}
}
총 O(V)번에 걸쳐서 최단 거리가 가장 짧은 노드를 매번 선형 탐색해야 한다.
따라서 전체 시간 복잡도는 0(V^2)
이다.
일반적으로 코딩 테스트의 최단 경로 문제에서
전체 노드의 개수가 5,000개 이하라면이 코드로 문제를 해결할 수 있다.
하지만 노드의 개수가 10,000개를 넘어가는 문제라면 어떻게 해야 할까?
우선순위 큐
를 사용하면 된다.
최단 거리가 가장 짧은 노드를 구할 때, 우선순위 큐를 사용하는 것이다.
import java.util.*;
class Node implements Comparable<Node> {
private int index;
private int distance;
public Node(int index, int distance) {
this.index = index;
this.distance = distance;
}
public int getIndex() {
return this.index;
}
public int getDistance() {
return this.distance;
}
// 거리(비용)가 짧은 것이 높은 우선순위를 가지도록 설정
@Override
public int compareTo(Node other) {
if (this.distance < other.distance) {
return -1;
}
return 1;
}
}
public class Main {
public static final int INF = (int) 1e9;
public static int n, m, start;
public static ArrayList<ArrayList<Node>> graph = new ArrayList<ArrayList<Node>>();
public static int[] d = new int[100001];
public static void dijkstra(int start) {
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.offer(new Node(start, 0));
d[start] = 0;
while(!pq.isEmpty()) {
Node node = pq.poll();
int dist = node.getDistance(); // 현재 노드까지의 비용
int now = node.getIndex(); // 현재 노드
if (d[now] < dist) continue;
for (int i = 0; i < graph.get(now).size(); i++) {
int cost = d[now] + graph.get(now).get(i).getDistance();
if (cost < d[graph.get(now).get(i).getIndex()]) {
d[graph.get(now).get(i).getIndex()] = cost;
pq.offer(new Node(graph.get(now).get(i).getIndex(), cost));
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
start = sc.nextInt();
for (int i = 0; i <= n; i++) {
graph.add(new ArrayList<Node>());
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int c = sc.nextInt();
// a번 노드에서 b번 노드로 가는 비용이 c라는 의미
graph.get(a).add(new Node(b, c));
}
Arrays.fill(d, INF);
dijkstra(start);
// 모든 노드로 가기 위한 최단 거리를 출력
for (int i = 1; i <= n; i++) {
if (d[i] == INF) {
System.out.println("INFINITY");
}
else {
System.out.println(d[i]);
}
}
}
}
힙 자료구조를 이용하는 다익스트라 알고리즘의 시간 복잡도는 0(ElogV)이다.