Dijkstra (다익스트라)

Hyun·2025년 9월 10일
0

알고리즘

목록 보기
20/21
post-thumbnail

다익스트라 알고리즘은 그래프 간선정보(단/양방향 상관X)가 주어졌을 때 한 정점에서 모든 정점까지의 최단거리를 각각 구하는 알고리즘이다. 그러나 음수 가중치 간선이 존재하는 경우 사용할 수 없다. 해당 경우에는 벨만 포드 알고리즘을 사용해야 한다.

다익스트라 알고리즘의 핵심은 현재 갈 수 있는 거리 중 매번 가장 짧은 정점을 찾으면, 논리적으로 더 짧은 경로가 새로 발견될 수 없기 때문에 해당 정점까지의 가장 짧은 거리는 그 순간에 확정되는 것이다.

그러면 인접 노드 중 가장 짧은 노드를 찾기 위해 우선순위 큐를 사용하면 된다. 만약에 특정 순간에 가장 거리가 짧은 정점을 확정을 지었어도, 다른 노드 B로부터 시작 정점->노드 B -> 해당 정점까지의 거리를 기록한 노드(해당 정점까지의 누적 거리합)이 우선순위 큐에 여전히 남아있을 수도 있다.

그러나 이 부분은 인접 노드 삽입 시 매번 해당 노드로의 가장 작은 거리를 찾아 업데이트 했던 dist 배열에서 일치여부를 확인 if (d > dist[u]) continue; 하여 일치하지 않는다면(최단 거리로 갱신된 정보가 아니라면) 건너뛴다.
*d 는 우선순위큐에서 뽑은 정점까지의 누적 거리
*w 는 뽑은 정점이 가지고 있었던 특정 인접 정점까지의 거리 정보

for문 내부에서 if (dist[v] > d + w) 이 조건문은 최단거리를 갱신된 정점에 대해 인접한 정점들을 돌면서, 기존에 기록했던 인접 정점까지의 최단거리(dist[v])보다, 최단거리 갱신 정점을 거쳐서 해당 노드로 가는게 더 빠른 경우에만 dist 를 갱신하고, 우선순위 큐에 삽입해주면 된다.

import java.io.*;
import java.util.*;

class Edge {
    int to;
    int weight;
    Edge(int to, int weight) {
        this.to = to;
        this.weight = weight;
    }
}

class PQNode implements Comparable<PQNode> {
    int vertex;
    int dist; // 시작점으로부터의 현재까지의 거리
    PQNode(int vertex, int dist) {
        this.vertex = vertex;
        this.dist = dist;
    }
    @Override
    public int compareTo(PQNode o) {
        return Integer.compare(this.dist, o.dist); // 최소 힙
    }
}

public class Main {

    static final int INF = 1_000_000_000;
    static int V, E, K;
    static int[] dist;
    static List<Edge>[] graph;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        V = Integer.parseInt(st.nextToken()); // 정점 개수
        E = Integer.parseInt(st.nextToken()); // 간선 개수
        K = Integer.parseInt(br.readLine());  // 시작 정점

        dist = new int[V + 1];
        Arrays.fill(dist, INF);

        graph = new ArrayList[V + 1];
        for (int i = 1; i <= V; i++) graph[i] = new ArrayList<>();

        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());
            graph[u].add(new Edge(v, w));
        }

        dijkstra(K);

        for (int i = 1; i <= V; i++) {
            if (dist[i] == INF) System.out.println("INF");
            else System.out.println(dist[i]);
        }
    }

    static void dijkstra(int start) {
        PriorityQueue<PQNode> pq = new PriorityQueue<>();
        dist[start] = 0;
        pq.offer(new PQNode(start, 0));

        while (!pq.isEmpty()) {
            PQNode cur = pq.poll();
            int u = cur.vertex;
            int d = cur.dist;

            // 최신 거리만 처리
            if (d != dist[u]) continue;

            for (Edge edge : graph[u]) {
                int v = edge.to;
                int w = edge.weight;

                if (dist[v] > d + w) {
                    dist[v] = d + w;
                    pq.offer(new PQNode(v, dist[v]));
                }
            }
        }
    }
}
profile
better than yesterday

0개의 댓글