방향 없는 그래프에서 1번 정점에서 N번 정점으로 가는 최단 경로를 구하는 문제.
단, 반드시 주어진 두 정점 v1, v2를 반드시 거쳐야 한다.
👉 즉, 경로는 두 가지 경우만 고려하면 된다.
1 → v1 → v2 → N
1 → v2 → v1 → N
위 두 경로 중 더 짧은 것을 정답으로 출력하면 된다.
만약 경로가 불가능하다면 -1을 출력한다.
다익스트라 3번 실행
1에서 시작하는 최단 거리 v1에서 시작하는 최단 거리 v2에서 시작하는 최단 거리 두 가지 경로 거리 계산
최솟값 출력
-1 출력 | 단계 | 설명 |
|---|---|
| 1 | 그래프 입력 받기 (인접 리스트 활용) |
| 2 | 다익스트라 함수 구현 (우선순위 큐 사용) |
| 3 | 1, v1, v2에서 다익스트라 실행 |
| 4 | 두 가지 경우 거리 계산 |
| 5 | 가능한 경우 중 최솟값 출력, 불가능하면 -1 |

package Baekjoon;
import java.io.*;
import java.util.*;
public class B_1504_특정한최단경로 {
static int N, E;
static List<int[]>[] graph; // [정점, 가중치]
static final int INF = 1_000_000_000; // 충분히 큰 값
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
E = Integer.parseInt(st.nextToken());
graph = new ArrayList[N + 1];
for (int i = 1; i <= N; i++) {
graph[i] = new ArrayList<>();
}
// 간선 입력
for (int i = 0; i < E; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
graph[a].add(new int[]{b, c});
graph[b].add(new int[]{a, c}); // 양방향
}
st = new StringTokenizer(br.readLine());
int v1 = Integer.parseInt(st.nextToken());
int v2 = Integer.parseInt(st.nextToken());
// 다익스트라 3번 실행
int[] dist1 = dijkstra(1);
int[] distV1 = dijkstra(v1);
int[] distV2 = dijkstra(v2);
// 경우1: 1 → v1 → v2 → N
long case1 = (long) dist1[v1] + distV1[v2] + distV2[N];
// 경우2: 1 → v2 → v1 → N
long case2 = (long) dist1[v2] + distV2[v1] + distV1[N];
long ans = Math.min(case1, case2);
if (ans >= INF) System.out.println(-1);
else System.out.println(ans);
}
// 다익스트라
static int[] dijkstra(int start) {
int[] dist = new int[N + 1];
Arrays.fill(dist, INF);
dist[start] = 0;
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
pq.add(new int[]{start, 0}); // [정점, 거리]
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int now = cur[0];
int cost = cur[1];
if (cost > dist[now]) continue;
for (int[] next : graph[now]) {
int nextNode = next[0];
int nextCost = cost + next[1];
if (nextCost < dist[nextNode]) {
dist[nextNode] = nextCost;
pq.add(new int[]{nextNode, nextCost});
}
}
}
return dist;
}
}
int[] dist = new int[N + 1];
Arrays.fill(dist, INF); // 모든 거리를 무한대로 초기화
dist[start] = 0; // 시작 정점의 거리는 0
👉 처음에는 모든 정점까지의 거리를 무한대(INF)로 설정하고, 시작 정점의 거리를 0으로 둔다.
PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
pq.add(new int[]{start, 0}); // [정점 번호, 현재까지의 거리]
👉 PriorityQueue는 현재까지의 거리가 가장 짧은 정점을 우선적으로 꺼내기 위해 사용한다.
즉, 항상 가장 가까운 정점부터 탐색할 수 있게 해준다.
👉 여기서 Comparator.comparingInt(a -> a[1])는 큐 안의 요소를 두 번째 값, 즉 거리 기준으로 오름차순 정렬하겠다는 의미이다.
따라서 거리가 작은 정점이 큐에서 먼저 나오게 됩니다.
while (!pq.isEmpty()) {
int[] cur = pq.poll();
int now = cur[0]; // 현재 정점
int cost = cur[1]; // 현재까지의 거리
if (cost > dist[now]) continue; // 이미 더 짧은 경로가 있으면 무시
👉 우선순위 큐에서 하나 꺼낸다.
이미 더 짧은 경로(dist[now])가 존재한다면 스킵한다.
for (int[] next : graph[now]) {
int nextNode = next[0]; // 인접한 정점
int nextCost = cost + next[1]; // 현재 비용 + 간선 가중치
👉 현재 정점(now)에 연결된 인접 정점들을 확인한다.
그 정점까지 가는 새로운 거리(nextCost)를 계산한다.
if (nextCost < dist[nextNode]) {
dist[nextNode] = nextCost; // 더 짧은 거리로 갱신
pq.add(new int[]{nextNode, nextCost}); // 큐에 삽입
}
}
}
👉 만약 새로운 경로가 더 짧으면, dist[nextNode] 값을 갱신
pq에 다시 넣어서 나중에 탐색할 수 있도록 한다.
return dist;
👉 최종적으로 dist 배열에는 시작 정점에서 각 정점까지의 최단 거리가 저장된다.
다익스트라 알고리즘은 하나의 시작 정점에서 모든 정점까지의 최단 경로를 구하는 알고리즘이다.
간선의 가중치가 음수일 수 없다는 조건이 붙으며, 네트워크 경로 탐색이나 지도 서비스 등 다양한 분야에서 사용된다.
다익스트라는 기본적으로 가까운 정점부터 탐색하는 방식을 따른다.
예를 들어, 시작 정점이 1번이고 다른 정점들과 연결된 그래프가 있다고 하자.
[0, ∞, ∞, ∞, ...] 최종적으로 시작점에서 각 정점까지의 최단 거리가 구해진다.