다익스트라 알고리즘

다익스트라 알고리즘

문제

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

86-1.png

설명

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

출력

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

입력 예제 1

6 9
1 2 12 // 1번 정점에서 2번정점으로 가는데 12의 비용이 든다. 
1 3 4 
2 1 2
2 3 5
2 5 5
3 4 5
4 2 2 
4 5 5
6 4 5

출력 예제 1

2 : 11
3 : 4
4 : 9
5 : 14
6 : impossible

해결방법

86.png

  • 위 메모는 O(n)으로 푸는 방식을 설명한 그림. 다익스트라와 비슷하나 for문 도는 것 자체가 비용이 엄청나게 듬
  • 따라서, 이를 해결하기 위한 방법으로 우선순위 큐를 사용하는 다익스트라 알고리즘을 사용하여 문제를 해결
  • 다익스트라 알고리즘에서는 각 간선으로 가는 비용이 음수가 될 수 없음.

코드

import java.util.*;

// 간선 객체 생성
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;
  }
}

class Main {
  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));
    // 시작 정점은 최소거리 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) {
    Main T = new Main();
    Scanner kb = new Scanner(System.in);
    n = kb.nextInt();
    m = kb.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 = kb.nextInt();
      // 그래프 정점에서 갈 수 있는 정점
      int b = kb.nextInt();
      // 그 정점으로 가는 비용
      int c = kb.nextInt();
      // 위 값으로 객체 삽입
      graph.get(a).add(new Edge(b, c));
    }
    // 수행.
    T.solution(1);
    // 2번 정점 부터 찍는다. 만약 배열에 최대값이 초기화 되지 않고 있다면 가는게 불가능 하므로
    // 불가능을 찍는다.
    for (int i = 2; i <= n; i++) {
      if (dis[i] != Integer.MAX_VALUE) System.out.println(i + " : " + dis[i]);
      else System.out.println(i + " : impossible");
    }
  }
}

© 2024. Chiptune93 All rights reserved.