3 분 소요

다익스트라(Dijkstra)

: 출발점에서 목표점까지의 최단경로를 구하는 알고리즘.

  • 다익스트라 알고리즘을 돌고 나면 출발점으로부터 각 노드들까지의 모든 최단경로를 다 구할 수 있음.

  • 간선에 음의 가중치가 없어야 사용이 가능한 알고리즘.

  • 그리디(다음 노드는 가장 작은 값을 가지는 노드를 선택하며 최단경로를 구해나간다) + DP(각 노드마다의 최단경로를 기록한 DP테이블이 있으며, 최소값이 나타날때 업데이트를 한다.)

  • 알고리즘 복잡도: O(ElogV) (E: 간선 수, V: 노드 수)


구현방법

1. 기본 구현

import java.util.ArrayList;

public class Dijkstra {

    static class Node {
        int to;
        int weight;

        public Node(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }
    }
   
    public static void dijkstra1(int v, int[][] data, int start) {
        ArrayList<ArrayList<Node>> graph = new ArrayList<>();
        for (int i = 0; i < v + 1; i++) {
            graph.add(new ArrayList<>());
        }

        for (int i = 0; i < data.length; i++) {
            graph.get(data[i][0]).add(new Node(data[i][1], data[i][2]));
        }

        int[] distanceDP = new int[v + 1];
        for (int i = 1; i < v + 1; i++) {
            distanceDP[i] = Integer.MAX_VALUE;
        }
        distanceDP[start] = 0;

        boolean[] visited = new boolean[v + 1];

        for (int i = 0; i < v; i++) {
            int minDist = Integer.MAX_VALUE;
            int curIdx = 0;
            for (int j = 1; j < v + 1; j++) {
                if(!visited[j] && distanceDP[j] < minDist) {
                    minDist = distanceDP[j];
                    curIdx = j;
                }

            }
            visited[curIdx] = true;

            for (int j = 0; j < graph.get(curIdx).size(); j++) {
                Node adjNode = graph.get(curIdx).get(j);
                if(distanceDP[adjNode.to] > distanceDP[curIdx] + adjNode.weight) {
                    distanceDP[adjNode.to] = distanceDP[curIdx] + adjNode.weight;
                }
            }
        }

        for (int i = 1; i < v + 1; i++) {
            if(distanceDP[i] == Integer.MAX_VALUE) {
                System.out.print("NO WAY ");
            } else {
                System.out.print(distanceDP[i] + " ");
            }
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        int[][] data = { {1, 2, 2}, {1, 3, 3}, {2, 3, 4}, {2, 4, 5}, {3, 4, 6} };
        dijkstra1(5, data, 1); // 0 2 3 7 NO WAY 
    }
}

2. 우선순위 큐

  • 필요한 것
    • Node 클래스
    • ArrayList<ArrayList>
    • DP배열(정점 수만큼): 최소거리 업데이트 용
    • 우선순위 큐: 가중치 정렬
import java.util.ArrayList;
import java.util.PriorityQueue;

public class Dijkstra {

    static class Node {
        int to;
        int weight;

        public Node(int to, int weight) {
            this.to = to;
            this.weight = weight;
        }
    }
    
    public static void dijkstra2(int v, int[][] data, int start) {
        // 각 노드를 담을 리스트 + 간선정보를 담을 리스트
        ArrayList<ArrayList<Node>> graph = new ArrayList<>();
        // 노드 수만큼 List 만들기 (노드가 1부터 시작해서 인덱스는 v + 1로 관리)
        for (int i = 0; i < v + 1; i++) {
            graph.add(new ArrayList<>());
        }
        // 출발노드(data[i][0]) 리스트 위치에 노드(to, weight) 추가 -> 그래프 리스트 완성
        for (int i = 0; i < data.length; i++) {
            graph.get(data[i][0]).add(new Node(data[i][1], data[i][2]));
        }

        // DP배열 (최소거리 업데이트용)
        int[] distanceDP = new int[v + 1];
        for (int i = 1; i < v + 1; i++) {
            distanceDP[i] = Integer.MAX_VALUE; // 최대값으로 초기화
        }
        distanceDP[start] = 0; // 시작점은 거리를 0으로

        // 가중치 정렬 우선순위큐
        PriorityQueue<Node> pq = new PriorityQueue<>((x, y) -> x.weight - y.weight);
        pq.offer(new Node(start, 0)); // 큐에 임의의 노드 넣어 시작
        // 큐가 빌때까지
        while(!pq.isEmpty()) {
            Node curNode = pq.poll();
            // 연결하려는 노드의 기존 가중치가(DP) 현재 연결하려는 가중치(curNode.weight)보다 작으면 그냥 둠
            if(distanceDP[curNode.to] < curNode.weight) {
                continue;
            }
            // 크거나 같으면 인접노드 체크하면서 업데이트
            for (int i = 0; i < graph.get(curNode.to).size(); i++) {
                Node adjNode = graph.get(curNode.to).get(i); //인접노드 픽
                // 그게 기존 가중치(DP)보다 현재 연결해서 만들어지는 가중치가 작으면 업데이트
                if(distanceDP[adjNode.to] > curNode.weight + adjNode.weight) {
                    distanceDP[adjNode.to] = curNode.weight + adjNode.weight;
                    pq.offer(new Node(adjNode.to, distanceDP[adjNode.to])); // 그리고 나머지 간선정보 큐에 추가
                }
            }
        }

        for (int i = 1; i < v + 1; i++) {
            if(distanceDP[i] == Integer.MAX_VALUE) {
                System.out.print("NO WAY ");
            } else {
                System.out.print(distanceDP[i] + " ");
            }
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[][] data = { {1, 2, 2}, {1, 3, 3}, {2, 3, 4}, {2, 4, 5}, {3, 4, 6} };
        dijkstra2(5, data, 1); // 0 2 3 7 NO WAY 
    }
}

마지막 수정일시: 2022-07-19 23:17

댓글남기기