Algorithm/Theory

[ 그래프 최단경로 ] 다익스트라

youth787 2023. 9. 29. 21:47

최단 경로 구하기

하나의 시작 정점에서 끝 정점가지의 최단 경로를 구한다.

다익스트라 알고리즘은 음의 가중치를 허용하지 않는다.

탐욕 기법을 사용한 알고리즘. MST(Minimum spanning tree)의 프림 알고리즘과 유사.

 

동작 과정 

1. 출발 노드를 설정.

2. 출발 노드를 기준으로 각 노드의 최소 비용을 저장.

3. 방문하지 않은 노드 중에서 가장 비용이 적은 노드를 선택.

4. 해당 노드를 거쳐서 특정한 노드로 가는 경우를 고려하여 최소 비용을 갱신한다.

5. 위 과정에서 3~4번을 반복한다. 

다익스트라 - 우선순위 큐 

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

public class 다익스트라_PQ {
	static class Node implements Comparable<Node> {
		int v, w;

		public Node(int v, int w) {
			this.v = v;
			this.w = w;
		}

		@Override
		public int compareTo(Node o) {
			return Integer.compare(this.w, o.w);
		}

		@Override
		public String toString() {
			return "Node [v=" + v + ", w=" + w + "]";
		}
	}

	static final int INF = Integer.MAX_VALUE;
	static int V, E;
	static List<Node>[] adjList; // 인접리스트
	static int[] dist;

	public static void main(String[] args) {
		Scanner sc = new Scanner(input);

		V = sc.nextInt();
		E = sc.nextInt();

		adjList = new ArrayList[V];
		for (int i = 0; i < V; i++) {
			adjList[i] = new ArrayList<>();
		}

		dist = new int[V];
		Arrays.fill(dist, INF);
        
		for(int i = 0 ; i<E; i++) {
			int A = sc.nextInt();
			int B = sc.nextInt();
			int W = sc.nextInt();
			//유향 그래프
			adjList[A].add(new Node(B, W)); //인접리스트 삽입
		}//입력 끝
		
		dijkstra(0);
		System.out.println(Arrays.toString(dist));
	}

	private static void dijkstra(int start) {
		PriorityQueue<Node> pq = new PriorityQueue<>();
		
		boolean[] visited = new boolean[V]; //방문처리
		
		pq.add(new Node(start, 0));
		dist[start] = 0;			//시작 노드까지 거리는 0
		
		while(!pq.isEmpty()) {
			Node curr = pq.poll();
			
			if(visited[curr.v])continue;
			visited[curr.v]= true;
			
			//갱신 하는 작업
			for(Node n : adjList[curr.v]) {
				if(!visited[n.v] && dist[n.v] > dist[curr.v] + n.w) {
					dist[n.v]= dist[curr.v]+ n.w;
					pq.add(new Node(n.v, dist[n.v]));
				}
			}
			System.out.println(pq);
		}
	}

	static String input = "6 11\r\n" + "0 1 4\r\n" + "0 2 2\r\n" + "0 5 25\r\n" + "1 3 8\r\n" + "1 4 7\r\n"
			+ "2 1 1\r\n" + "2 4 4\r\n" + "3 0 3\r\n" + "3 5 6\r\n" + "4 3 5\r\n" + "4 5 12\r\n" + "";
}

 

다익스트라 - 반복문 

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

public class 다익스트라_반복문 {
	static class Node {
		int v, w;

		public Node(int v, int w) {
			this.v = v;
			this.w = w;
		}
	}

	static final int INF = Integer.MAX_VALUE;
	static int V, E; // V :정점의 수 , E : 간선의수
	static List<Node>[] adjList; // 인접리스트
	static int[] dist; // 최단 길이를 저장할 배열

	public static void main(String[] args) {
		Scanner sc = new Scanner(input);

		V = sc.nextInt();
		E = sc.nextInt();

		adjList = new ArrayList[V]; 
		for (int i = 0; i < V; i++) {
			adjList[i] = new ArrayList<>();
		}
        
		dist = new int[V]; // 거리값을 저장할 배열 
		Arrays.fill(dist, INF); // 초기값은 무한대로 채운다. 

		for (int i = 0; i < E; i++) {
			int A = sc.nextInt(); // 시작정점
			int B = sc.nextInt(); // 도착정점
			int W = sc.nextInt(); // 가중치

			// 유향 그래프
			adjList[A].add(new Node(B, W)); // 인접리스트에 노드 추가
		} // 입력 끝

		dijkstra(0);
		System.out.println(Arrays.toString(dist));
	}

	static void dijkstra(int start) {
		boolean[] visited = new boolean[V];
		
		dist[start] = 0;//시작 정점까지의 거리는 0으로 초기화
		
		for(int i = 0 ; i<V-1; i++) { // V-1, V 둘다 괜찮다. 
			int min = INF;
			int idx = -1;
			
			//선택하지 않은 정점 중 dist가 가장 작은 값을 골라 
			for(int j = 0 ; j<V; j++) {
				if(!visited[j] && min > dist[j]) {
					min = dist[j];
					idx = j;
				}
			}
			if(idx == -1) break; // 선택할 정점이 없다.
			
			visited[idx] = true; //선택
			
			for(int j = 0; j<adjList[idx].size(); j++) {
				Node curr = adjList[idx].get(j);
				
				//방문하지 않았고, 연결 되어있으면서 (인접리스트라 확인하지 않아도 된다)
				//이미 가지고 있는 값보다 갱신할 여지가 있으면 갱신.
				if(!visited[curr.v] && dist[curr.v] > dist[idx]+curr.w) {
					dist[curr.v] = dist[idx] + curr.w;
				}
			}
		}
	}
	static String input = "6 11\r\n" + "0 1 4\r\n" + "0 2 2\r\n" + "0 5 25\r\n" + "1 3 8\r\n" + "1 4 7\r\n"
			+ "2 1 1\r\n" + "2 4 4\r\n" + "3 0 3\r\n" + "3 5 6\r\n" + "4 3 5\r\n" + "4 5 12\r\n" + "";

}
반응형