그래프 알고리즘 기초 - 다익스트라(Dijkstra)


그래프 알고리즘 기초 - 다익스트라(Dijkstra)

다익스트라(Dijkstra)

  • 다익스트라 알고리즘은 시작노드에서 모든 노드로의 최단거리를 찾는 알고리즘입니다.
  • 참고사항
    • 시간복잡도(노드수 : v, 에지 수 : E) : O(Elogv)
    • 음수 가중치가 있는경우 사용 할 수 없음. 음수 가중치가 있는 경우 벨만포드 알고리즘(Bellman-Ford) 을 사용.
  • 알고리즘 활용 영역

다익스트라 구현 코드(백준-최단경로)

 public class BJ_1753 {
  /**
   * 방향그래프가 주어지면 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하시오. 단, 모든 간선의 가중치는 10 이하의 자연수이다.
   * 첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다.
   * 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가 주어진다. 셋째 줄부터 E개의 줄에 걸쳐 각 간선을 나타내는 세 개의 정수 (u, v, w)가 순서대로 주어진다.
   * 이는 u에서 v로 가는 가중치 w인 간선이 존재한다는 뜻이다. u와 v는 서로 다르며 w는 10 이하의 자연수이다. 서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수도 있음에 유의한다.
   *
   *
   * 입력값
   *
   5 6
   1
   5 1 1
   1 2 2
   1 3 3
   2 3 4
   2 4 5
   3 4 6
   *
   * @param args
   */
  public static void main(String[] args) throws IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String[] VE = br.readLine().split(" ");
    int v = Integer.parseInt(VE[0]);
    int e = Integer.parseInt(VE[1]);
    int k = Integer.parseInt(br.readLine());

    int[] answer = new int[v + 1];              //각 노드에서 최단거리를 입력할 결과 배열 (시작노드는 0으로, 나머지는 무한대(∞)로 입력한다.)
    Arrays.fill(answer, Integer.MAX_VALUE);     //가장 큰값으로 초기화

    boolean[] visited = new boolean[v + 1];     //방문 정보관리
    List<Node>[] nodes = new ArrayList[v+1];    //2차원 배열을 생성 하여 그래프 정보를 입력한다.
    for(int i = 0; i <= v; i++){
      nodes[i] = new ArrayList<>();
    }

    for(int i = 0; i < e; i ++){
      String[] SEV = br.readLine().split(" ");
      int sn = Integer.parseInt(SEV[0]);    //시작 노드
      int en = Integer.parseInt(SEV[1]);    //종료(다음) 노드
      int vn = Integer.parseInt(SEV[2]);    //가중치

      nodes[sn].add(new Node(en, vn));      //2차원 배열에 입력. list의 Index(sn) 가 노드 번호가 된다.
    }

    Dijkstra(visited, nodes, answer, k);

    //출력 부분-------------------
    StringBuilder sb = new StringBuilder();
    for(int i = 1; i < answer.length; i++){
      if(answer[i] == Integer.MAX_VALUE){
        sb.append("INF").append("\n");      //더이상 갈수 있는 노드가 없다면 INF 로 출력 (무한대(∞) 로 남아있다는 것은 더이상 갈 수 있는 노드가 없다는 것을 뜻함.)
        continue;
      }
      sb.append(answer[i]).append("\n");
    }
    System.out.println(sb);   // 출력 : 0, 2, 3, 7, INF
    //출력 부분-------------------
  }

  private static void Dijkstra(boolean[] visited, List<Node>[] nodes, int[] answer, int k) {
    PriorityQueue<Node> queue = new PriorityQueue<>();
    queue.add(new Node(k, 0));
    answer[k] = 0; //시작 노드는 0으로 초기화.
    while(!queue.isEmpty()){
      Node curNode = queue.poll();
      if(visited[curNode.end]){
        continue;   //방문한 노드이면 패스.
      }
      visited[curNode.end] = true;       //방문 체크
      for(Node nextNode : nodes[curNode.end]){
        if(answer[nextNode.getEnd()] > answer[curNode.getEnd()] + nextNode.weight){
          answer[nextNode.getEnd()] = answer[curNode.getEnd()] + nextNode.weight;    //가중치 업데이트
          queue.add(new Node(nextNode.getEnd(), answer[nextNode.getEnd()]));
        }
      }
    }
  }

  public static class Node implements Comparable<Node>{
    private int end;
    private int weight;

    public Node(int end, int weight) {
      this.end = end;
      this.weight = weight;
    }

    public int getEnd() {
      return end;
    }

    public int getWeight() {
      return weight;
    }

    @Override
    public int compareTo(Node o) {
      return weight - o.weight;
    }
  }
}

풀이

주어진 그래프는 아래와 같습니다.

1753_그래프

  • 결과

    노드번호 1 2 3 4 5
    최단거리 : 0, 2, 3, 7, INF

결과에서 보듯이 시작노드(K = 1) 에서 갈 수 있는 최단경로 가중치가 구해진걸 확인 할 수 있습니다.

  • 1 -> 2 으로 가는 최단경로의 가중치는 2
  • 1 -> 3 으로 가는 최단경로의 가중치는 3
  • 1 -> 4 으로 가는 최단경로의 가중치는 7 (1 -> 2-> 4 의 경로로 이동)
  • 1 -> 5 는 갈 수 없기 때문에 INF

Back to blog