본문 바로가기
카테고리 없음

다익스트라 알고리즘

by _비니_ 2024. 5. 25.

설명

아래의 가중치 방향그래프에서 1번 정점에서 모든 정점으로의 최소 거리비용을 출력하는 프로그램을 작성하세요. (경로가 없으면 impossible을 출력한다.)

 

입력

첫째 줄에는 정점의 수 N(1<=N<=20)와 간선의 수 M가 주어진다. 그 다음부터 M줄에 걸쳐 연결정보와 거리비용이 주어진다.

 

출력
1번 정점에서 각 정점으로 가는 최소비용을 2번 정점부터 차례대로 출력하세요.

 

 

문제 해결
다익스트라 알고리즘

다익스트라 알고리즘은 다이나믹 프로그래밍을 활용한 대표적인 최단경로 탐색 알고리즘이다.

음의 가중치(음의 간선, 음의 값)가 없는 그래프의 한 노드에서 각 모든 노드까지의 최단거리를 구하는
알고리즘을 말한다.

 

 

 

다익스트라 알고리즘의 메커니즘은 기본적으로 아래 두 단계를 반복하여 임의의 노드에서 각 모든 노드까지의 최단거리를 구하는 문제에서 활용할 수 있다.

 

임의의 노드에서 다른 노드로 가는 값을 비용이라고 한다.

  • 방문하지 않은 노드 에서 가장 비용이 적은 노드를 선택  (그리디 알고리즘)
  • 해당 노드로부터 갈 수 있는 노드들의 비용을 갱신 (다이나믹 프로그래밍) 

가능한 적은 비용으로 가장 빠르게 해답에 도달하는 경로를 찾아내는 대부분의 문제에 응용된다!!

 

class Edge implements Comparable<Edge> {

    public int vex;
    public int cost;

    Edge(int vex, int cost) {
        this.vex = vex;
        this.cost = cost;
    }

    @Override
    public int compareTo(Edge ob) {
        return this.cost - ob.cost;
    }
}
  • Edge 클래스는 그래프의 간선을 나타내며, 정점 번호인 vex와 비용 cost를 담고 있다.
  • 우선순위 큐에 넣기 위해 Comparable 인터페이스를 구현해 비용을 기준으로 정렬한다.
    • 이 떄 비용이 작은 것을 우선순위로 두었다.

 

public static void main(String[] args) {
    P05_다익스트라알고리즘 T = new P05_다익스트라알고리즘();
    Scanner in = new Scanner(System.in);
    n = in.nextInt();
    m = in.nextInt();
    graph = new ArrayList<ArrayList<Edge>>();
    for (int i = 0; i <= n; i++) {
        graph.add(new ArrayList<Edge>());
    }
    dis = new int[n + 1];
    Arrays.fill(dis, Integer.MAX_VALUE);
    for (int i = 0; i < m; i++) {
        int a = in.nextInt();
        int b = in.nextInt();
        int c = in.nextInt();
        graph.get(a).add(new Edge(b, c));
    }

    T.solution(1);
    for (int i = 2; i <= 2; i++) {
        if (dis[i] != Integer.MAX_VALUE) System.out.println(i + " : " + dis[i]);
        else System.out.println(i + " : impossible");
    }
}
  • 우선 모든 정점까지의 거리를 무한대로 초기화시켜준다

  • 그리고 for문을 돌며 입력받아 그래프의 인접 리스트를 구성한다.
  • 1번 정점에서 모든 정점으로 가는 최소 거리비용 구해야하므로 1에서 다익스트라 알고리즘을 수행한다.

 

<다익스트라 알고리즘>

public void solution(int v) {
    PriorityQueue<Edge> pQ = new PriorityQueue<>();
    pQ.offer(new Edge(v, 0));
    dis[v] = 0;
    while (!pQ.isEmpty()) {
        Edge tmp = pQ.poll();
        int now = tmp.vex;
        int nowCost = tmp.cost;
        if (nowCost > dis[now]) continue;
        for (Edge ob : graph.get(now)) {
            if (dis[ob.vex] > nowCost + ob.cost) {
                dis[ob.vex] = nowCost + ob.cost;
                pQ.offer(new Edge(ob.vex, nowCost + ob.cost));
            }
        }
    }
}
  • 우선순위큐 pQ를 선언해 현재 거리가 가장 짧은 정점을 우선적으로 처리하도록 한다.
    • pQ.offer(new Edge(v, 0)): 시작점을 비용 0으로 큐에 추가
    • dis[v] = 0: 시작점의 거리를 0으로 설정
  • 큐가 비어있지 않는 동안, 가장 비용이 적은 정점을 꺼내어 그 정점과 인접한 정점들의 거리를 갱신해간다.
    • if (nowCost > dis[now]) continue;: 이미 처리된 정점이면 continue
    • if (dis[ob.vex] > nowCost + ob.cost): 현재 정점을 거쳐서 가는 것이 더 짧은 경우 거리를 갱신하고, 해당 정점을 우선순위 큐에 추가

 

 

 

최종 코드

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;

public class P05_다익스트라알고리즘 {

    static int n, m;
    static ArrayList<ArrayList<Edge>> graph;
    static int[] dis;

    public void solution(int v) {
        PriorityQueue<Edge> pQ = new PriorityQueue<>();
        pQ.offer(new Edge(v, 0));
        dis[v] = 0;
        while (!pQ.isEmpty()) {
            Edge tmp = pQ.poll();
            int now = tmp.vex;
            int nowCost = tmp.cost;
            if (nowCost > dis[now]) continue;
            for (Edge ob : graph.get(now)) {
                if (dis[ob.vex] > nowCost + ob.cost) {
                    dis[ob.vex] = nowCost + ob.cost;
                    pQ.offer(new Edge(ob.vex, nowCost + ob.cost));
                }
            }
        }
    }

    public static void main(String[] args) {
        P05_다익스트라알고리즘 T = new P05_다익스트라알고리즘();
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        m = in.nextInt();
        graph = new ArrayList<ArrayList<Edge>>();
        for (int i = 0; i <= n; i++) {
            graph.add(new ArrayList<Edge>());
        }
        dis = new int[n + 1];
        Arrays.fill(dis, Integer.MAX_VALUE);
        for (int i = 0; i < m; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            int c = in.nextInt();
            graph.get(a).add(new Edge(b, c));
        }

        T.solution(1);
        for (int i = 2; i <= 2; i++) {
            if (dis[i] != Integer.MAX_VALUE) System.out.println(i + " : " + dis[i]);
            else System.out.println(i + " : impossible");
        }
    }
}

class Edge implements Comparable<Edge> {

    public int vex;
    public int cost;

    Edge(int vex, int cost) {
        this.vex = vex;
        this.cost = cost;
    }

    @Override
    public int compareTo(Edge ob) {
        return this.cost - ob.cost;
    }
}
반응형