코딩테스트/백준

[백준 1753] 최단경로 (Java) - 다익스트라 (메모리 초과 엔딩..)

imachill7guy 2025. 3. 22. 20:03

https://www.acmicpc.net/problem/1753

최단경로

문제

방향그래프가 주어지면 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하시오. 단, 모든 간선의 가중치는 10 이하의 자연수이다.

입력

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1 ≤ V ≤ 20,000, 1 ≤ E ≤ 300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1 ≤ K ≤ V)가 주어진다. 셋째 줄부터 E개의 줄에 걸쳐 각 간선을 나타내는 세 개의 정수 (u, v, w)가 순서대로 주어진다. 이는 u에서 v로 가는 가중치 w인 간선이 존재한다는 뜻이다. u와 v는 서로 다르며 w는 10 이하의 자연수이다. 서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수도 있음에 유의한다.

출력

첫째 줄부터 V개의 줄에 걸쳐, i번째 줄에 i번 정점으로의 최단 경로의 경로값을 출력한다. 시작점 자신은 0으로 출력하고, 경로가 존재하지 않는 경우에는 INF를 출력하면 된다.

예제 입력 1 복사

5 6
1
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6

예제 출력 1 복사

0
2
3
7
INF

풀이
package gold;

import java.io.*;
import java.util.*;

public class 최단경로 {
    static int N,E,S;
    static boolean[] visited;
    static int[] distance;
    static ArrayList<int[]>[] A;

    public static void main(String[] args)throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine()); // 1번째 줄 읽음
        N = Integer.parseInt(st.nextToken()); // 노드개수
        E = Integer.parseInt(st.nextToken()); // 에지개수
        visited = new boolean[N+1]; // 노드번호 1부터 시작
        distance = new int[N+1]; // 최단거리 배열
        int max = Integer.MAX_VALUE;
        Arrays.fill(distance, max); // distance 배열 값 모두 max값으로 채우기
        A = new ArrayList[N+1];

        // 인접노드 리스트 초기화
        for(int i=1; i<N+1; i++){
            A[i] = new ArrayList<>();
        }

        S = Integer.parseInt(br.readLine()); // 2번째 줄 : 시작노드
        distance[S] = 0; // 출발노드는 최단경로 0으로 update

        for(int i=0; i<E; i++){
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken()); // 출발노드
            int end = Integer.parseInt(st.nextToken()); // 도착노드
            int weight = Integer.parseInt(st.nextToken()); // 가중치
            A[start].add(new int[] {end, weight});
        }
        // 출발노드부터 다익스트라 시작
        dijkstra(S);
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        for(int i=1; i<N+1; i++){
            if(distance[i] == max){
                bw.write("INF"+"\n");
            }else{
                bw.write(distance[i]+"\n");
            }
        }
        bw.flush();
        bw.close();
    }
    private static void dijkstra(int start){
        // distance 배열 오름차순 정렬 우선순위 큐
        PriorityQueue<Integer> q = new PriorityQueue<>(Comparator.comparingInt(a -> distance[a]));
        q.add(start);
        while (!q.isEmpty()){
            int now = q.poll(); // 거리 가장 짧은 노드
            visited[now] = true; // 현재 노드 방문처리
            for(int[] next : A[now]){ // 현재 노드의 인접리스트 순회
                int nextNode = next[0]; // 다음 노드
                int weight = next[1]; // 가중치
                if(!visited[nextNode]){
                    distance[nextNode] = Math.min(distance[nextNode], distance[now] + weight);
                    q.add(nextNode);
                }
            }
        }
    }
}
  • 1번째 줄 : 노드개수, 에지개수
  • 2번째 줄 : 출발 노드 번호
  • 3번째줄 ~ : 출발노드, 도착노드, 가중치
    • 입력값으로 (출발노드, 도착노드, 가중치)를 기록하기 위해서
    • A[출발노드].add(new int[] {도착노드, 가중치}) 형태로 저장해준다.
  • 최단거리를 구하므로 distance 배열을 모두 Integer.MAX_VALUE로 채워준다.
  • 출발노드만 거리가 0이므로 출발노드 번호에만 distnace[출발노드] = 0으로 update해준다.
  • 출발노드부터 다익스트라 수행
  • dijkstra
    • distance 배열 value기준 오름차순 정렬 우선순위 큐 선언 후 출발노드 큐에 넣어준다.
    • 큐가 빌 때까지 아래 동작 반복 수행
      • 큐에서 poll하여 현재노드값 now 뽑아준다.
      • 해당 노드 방문처리 visited[now] = true
      • now 노드의 인접리스트 순회한다. (다음노드, 가중치)
      • 다음노드nextNode를 방문한 적이 없다면
        • 최단거리 비교후, 큐에 넣어준다.
        • distance[nextNode]와 distance[now] + weight 비교 후 최솟값을 distance[nextNode]에 업데이트 해준다
  • 다익스트라 모두 수행 후 distance 배열의 값 모두 출력해준다.
    • 출력시 값이 Integer.MAX_VALUE와 같다면 INF 출력해준다.