https://www.acmicpc.net/problem/1504
다익스트라(Dijkstra) 문제입니다.
문제를 잘 보시면 그냥 최단 경로를 찾는 것이 아닌, 두 정점을 반드시 지나는 최단 경로를 찾는 문제입니다.
1번 정점에서 시작해 임의의 두 정점을 지나고 N번 정점을 지나야 하므로 우리는 2가지 방식으로 최단 경로를 구할 수 있습니다.
이 점을 이용해 문제를 풀어보겠습니다.
특정 정점까지의 거리를 관리하기 위해 클래스를 생성하겠습니다.
static class Node implements Comparable<Node> {
int idx, cost; // 정점 번호, 가중치(거리)
Node (int idx, int cost) {
this.idx = idx;
this.cost = cost;
}
@Override
public int compareTo(Node o) {
return this.cost - o.cost; // 가중치 오름차순 정렬
}
}
compareTo를 오버라이딩 해줍니다. graph = new ArrayList<>();
for (int i = 0; i <= n; i++) graph.add(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.get(a).add(new Node(b, c));
graph.get(b).add(new Node(a, c));
}
// 다익스트라 메서드
private static int[] dijkstra(int start) {
// 리턴할 거리 정보
dist = new int[n+1];
Arrays.fill(dist, INF);
dist[start] = 0;
// 최소 힙
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.add(new Node(start, 0)); // 이동한 노드(시작 지점), 이동한 거리(0)
while (!pq.isEmpty()) {
Node cur = pq.poll();
int u = cur.idx; // 현재 노드
int d = cur.cost; // 현재까지 이동 거리
if (dist[u] < d) continue; // 현재 노드의 이동거리가 이미 최소라면 continue
conitnue를 해주어야 합니다.(아니라면 시간 초과 발생) // 다음 노드 탐색
for (Node nxt : graph.get(u)) {
int v = nxt.idx; // 다음 노드
int w = nxt.cost; // 다음 노드까지의 거리
// 현재 저장된 다음 노드까지의 거리보다
// 현재 노드에서 다음 노드까지의 거리가 더 짧다면
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w; // 최솟값 갱신
pq.add(new Node(v, dist[v])); // 다음 노드, 다음 노드까지의 거리 삽입
}
}
}
return dist;
}
dist에 저장된 다음 노드의 거리가 "현재 노드 -> 다음 노드" 거리가 더 짧다면, 값을 업데이트해 줍니다.위에 설명했듯이, 우리는 임의의 두 노드를 지나는 2가지 경로를 고려할 수 있습니다.
그러기 위해선 각각의 노드에서 최소 경로를 탐색해야 합니다.
ex) 1 -> v1 -> v2 -> n
- (1 -> v1) 최소 경로
- (v1 -> v2) 최소 경로
- (v2 -> n) 최소 경로
int[] from1 = dijkstra(1);
int[] fromV1 = dijkstra(v1);
int[] fromV2 = dijkstra(v2);
3개의 시작 지점을 구했으니 각각의 도착 지점을 설정해 값을 구하면 됩니다.
int path1, path2;
// 1. 1 -> v1 -> v2 -> n
if (from1[v1] == INF || fromV1[v2] == INF || fromV2[n] == INF) path1 = INF;
else path1 = from1[v1] + fromV1[v2] + fromV2[n];
// 2. 1 -> v2 -> v1 -> n
if (from1[v2] == INF || fromV2[v1] == INF || fromV1[n] == INF) path2 = INF;
else path2 = from1[v2] + fromV2[v1] + fromV1[n];
int answer = Math.min(path1, path2);
System.out.println(answer == INF ? -1 : answer);
import java.io.*;
import java.util.*;
public class Main {
static class Node implements Comparable<Node> {
int idx, cost;
Node (int idx, int cost) {
this.idx = idx;
this.cost = cost;
}
@Override
public int compareTo(Node o) {
return this.cost - o.cost;
}
}
static final int INF = (int) 1e9;
static int n, e, v1, v2;
static int[] dist;
static List<ArrayList<Node>> graph;
private static int[] dijkstra(int start) {
dist = new int[n+1];
Arrays.fill(dist, INF);
dist[start] = 0;
PriorityQueue<Node> pq = new PriorityQueue<>();
pq.add(new Node(start, 0));
while (!pq.isEmpty()) {
Node cur = pq.poll();
int u = cur.idx;
int d = cur.cost;
if (dist[u] < d) continue;
for (Node nxt : graph.get(u)) {
int v = nxt.idx;
int w = nxt.cost;
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.add(new Node(v, dist[v]));
}
}
}
return dist;
}
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<>();
for (int i = 0; i <= n; i++) graph.add(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.get(a).add(new Node(b, c));
graph.get(b).add(new Node(a, c));
}
st = new StringTokenizer(br.readLine());
v1 = Integer.parseInt(st.nextToken());
v2 = Integer.parseInt(st.nextToken());
int[] from1 = dijkstra(1);
int[] fromV1 = dijkstra(v1);
int[] fromV2 = dijkstra(v2);
int path1, path2;
// 1. 1 -> v1 -> v2 -> n
if (from1[v1] == INF || fromV1[v2] == INF || fromV2[n] == INF) path1 = INF;
else path1 = from1[v1] + fromV1[v2] + fromV2[n];
// 2. 1 -> v2 -> v1 -> n
if (from1[v2] == INF || fromV2[v1] == INF || fromV1[n] == INF) path2 = INF;
else path2 = from1[v2] + fromV2[v1] + fromV1[n];
int answer = Math.min(path1, path2);
System.out.println(answer == INF ? -1 : answer);
}
}
다익스트라 알고리즘이 이해가 잘 안됐는데 도움이 많이 됐습니다!