본문 바로가기
알고리즘/개념

다익스트라 알고리즘(Dijkstra Algorithm)

by 귀월 2023. 9. 16.

다익스트라 알고리즘?

 - 한 정점에서 다른 정점까지의 최단 경로를 구하는 알고리즘.

 - 도착 정점 뿐만 아니라 다른 모든 정점까지의 최단 경로도 구할 수 있다.

 - 간선 가중치가 양수인 경우에만 사용할 수 있다.

   -> (음수 가중치를 고려해야 하는 경우 벨만-포드, 플로이드-워셜 알고리즘 사용)

 

수행 과정

  1. 시작 정점과 끝 정점 설정.

  2. 현재 정점과 연결된 정점 중 방문하지 않았고, 간선 가중치가 가장 작은 정점을 선택.

  3. 선택된 정점을 기준으로 간선 비용을 계산하여 최단 거리 테이블에 기록.

  4. 2와 3의 과정을 반복하여 끝 정점까지의 비용을 모두 계산

 

 

구현

BOJ 1753 최단 경로 

 

1. 각 정점간 방문 및 최단 거리를 확인할 배열을 선언.

2. 연결된 정점 중 간선 가중치가 가장 작은 간선을 선택하기 위해 우선순위 큐 사용.

 

3. 자기 자신과의 거리는 계산하지 않는다.

4. 우선 순위 큐에서 가중치가 가장 작은 간선을 선택하고, 모든 정점과의 거리를 연산할 때까지 반복하여 비교 연산 수행.

 

전체 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {

	static int v, e, k;
	static List<Node>[] nodeList;
	static class Node implements Comparable<Node>{
		int to;
		int weight;
		public Node(int to, int weight) {
			super();
			this.to = to;
			this.weight = weight;
		}
		@Override
		public int compareTo(Node o) {
			// TODO Auto-generated method stub
			return this.weight-o.weight;
		}
	}
	public static void main(String[] args) throws IOException {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		StringBuilder sb = new StringBuilder();
		
		// 정점의 개수 v
		v = Integer.parseInt(st.nextToken());
		// 간선의 개수 e
		e = Integer.parseInt(st.nextToken());
		// 시작 정점 k
		k = Integer.parseInt(br.readLine());
		
		// 정점 연결 정보를 저장할 List[]
		nodeList = new ArrayList[v+1];
		
		for(int i=1; i<=v; i++) {
			nodeList[i] = new ArrayList<>();
		}
		
		for(int i=0; i<e; i++) {
			st = new StringTokenizer(br.readLine());
			int from = Integer.parseInt(st.nextToken());
			int to = Integer.parseInt(st.nextToken());
			int weight = Integer.parseInt(st.nextToken());
			
			nodeList[from].add(new Node(to, weight));
		}
		
		// 방문체크 visit[]
		boolean[] visit = new boolean[v+1];
		// 최단거리 기록할 distance[]
		int[] distance = new int[v+1];
		
		// 최소 간선 가중치를 선택하기 위해 우선순위 큐 사용.
		PriorityQueue<Node> pq = new PriorityQueue<>();
		pq.add(new Node(k, 0));
		
		// 간선 비용 비교하기 위해.
		Arrays.fill(distance, Integer.MAX_VALUE);
		
		// 정점 자신과의 거리는 계산하지 않음.
		distance[k] = 0;
		
		while(!pq.isEmpty()) {
			Node cur = pq.poll();
			
			//방문했던 정점을 제외하기 위해 방문 체크
			if(visit[cur.to]) continue;
			visit[cur.to] = true;
			
			// 현재 정점과 연결된 모든 정점 탐색
			for(Node n : nodeList[cur.to]) {
				// distance에 기록되어 있는 다음 정점까지의 최소 가중치 합보다
				// 현재 정점까지의 가중치 + 현재 정점과 다음 정점간 가중치 합이 더 작다면
				if(distance[n.to]> distance[cur.to]+n.weight) {
					//가중치 갱신
					distance[n.to] = distance[cur.to]+n.weight;
					pq.add(new Node(n.to, distance[n.to]));
				}
			}
		}
		for(int i=1; i<=v; i++) {
			sb.append(distance[i]==Integer.MAX_VALUE ? "INF" : distance[i]).append("\n");
		}
		System.out.println(sb.toString());
	}

}
반응형
LIST

댓글