https://www.acmicpc.net/problem/1916
🚩다익스트라 (Dijkstra)
1916번 문제를 보자마자 기본적인 다익스트라 알고리즘으로 해결할 수 있겠다고 생각을 했습니다. 평소에 알고 있던 다익스트라 방식으로 구현을 진행했고, 예제 출력도 정상적으로 나왔기 때문에 정답 제출을 했는데요..
결과는 시간 초과입니다🥲
15% 지점에서 계속 시간 초과가 발생했고, 문제를 다시 확인해 보니 시간제한이 0.5초 인걸 확인할 수 있었습니다.
시간 복잡도를 개선하기 위해 코드 분석을 해봤지만 문제의 원인은 찾지 못했고 검색을 통해 해결책을 찾아보니, queue에서 poll() 연산을 수행할 때 해동 노드의 방문 여부를 확인하는 처리가 필요하다는 것을 알게 되었습니다.
'근데.. queue.add를 수행하기 전에 이미 방문 여부를 확인하고, 미방문을 노드만 추가하는데, 왜 poll() 시점에 다시 방문 처리를 해야 하는 걸까?'라는 의문이 들었습니다.
🤔 2번 방문 확인하는 이유는 뭐지..?
코드를 디버깅해본 결과, 아직 미방문 상태인 5번 노드에 대한 요청이 두 번 발생했고, 이로 인해 방문 PriorityQueue을 사용하고 있음에도 불구하고 동일한 노드에 대한 처리가 중복으로 수행되고 있었습니다.
이러한 중복 처리를 방지하고 실행 시간을 최적화하기 위해, poll() 연산 이후에 방문 여부를 한 번 더 확인하는 것이 필요했던 것입니다!
아래는 제출한 코드입니다.
import java.io.*;
import java.util.*;
class Node {
int end;
int weight;
public Node(int end, int weight) {
this.end = end;
this.weight = weight;
}
}
public class Main {
static ArrayList<Node>[] al;
static int[] result;
static boolean[] visited;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int N = Integer.parseInt(br.readLine());
int M = Integer.parseInt(br.readLine());
al = new ArrayList[N + 1];
result = new int[N + 1];
visited = new boolean[N + 1];
for (int i = 1; i <= N; i++) {
al[i] = new ArrayList<>();
result[i] = Integer.MAX_VALUE;
}
for (int i = 0; i < M; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
al[a].add(new Node(b, c));
}
st = new StringTokenizer(br.readLine());
int start = Integer.parseInt(st.nextToken());
int end = Integer.parseInt(st.nextToken());
result[start] = 0;
djk(start);
bw.write(result[end] + "");
bw.close();
}
public static void djk(int start) {
PriorityQueue<Node> queue = new PriorityQueue<>((o1, o2) -> o1.weight - o2.weight);
queue.add(new Node(start, 0));
while (!queue.isEmpty()) {
Node now = queue.poll();
if (visited[now.end]) continue; // 추가한 코드
for (Node next : al[now.end]) {
if (!visited[next.end]) {
if (next.weight + result[now.end] < result[next.end]) {
result[next.end] = next.weight + result[now.end];
queue.add(new Node(next.end, result[next.end]));
}
}
}
visited[now.end] = true;
}
}
}
'Algorithm' 카테고리의 다른 글
[백준] 16139 : 인간-컴퓨터 상호작용 (JAVA) (0) | 2024.12.02 |
---|---|
[백준] 10816 : 숫자 카드 2 (JAVA) (0) | 2024.11.18 |
[백준] 16953 : A -> B (JAVA) (1) | 2024.11.10 |
[백준] 11054 : 가장 긴 바이토닉 부분 수열 (JAVA) (1) | 2024.11.08 |
[백준] 13549 : 숨바꼭질 3 (JAVA) (0) | 2024.11.05 |