programmers/DFS-BFS

백준 2593번 : 엘리베이터 [자바]

Meluu_ 2025. 7. 11. 10:01

 

🧫 문제 분석

 

✔️ 출처

엘리베이터 플래티넘 5

 

📖 문제

 

 

최단경로 + BFS + 역추적 문제

 

이문제를 풀면서 메모리초과가 진짜 자꾸 나서 

정말 힘들었다.

 

여러번의 테스트 끝에 알아낸 것은

컬렉션에서

for (int i : list)

향상된 for문(for-each)는 내부적으로 Iterator 객체를 생성해서 순회한다.

때문에 수많은 엘리베이터를 갖는 리스트를 foreach로 접근했으니

메모리초과될 수밖에 없었다. 

 

많은 양의 요소를 담는 컬렉션 객체는 되도록이면 for-each문을 사용하지 말아야겠다. 

 

그리고 거리는 dist배열로 따로 빼자.

괜히 큐에 같이넣어서 메모리초과뜬다.

 


🔅 문제 풀이 [다익스트라]

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

public class Main {

    static int N, M;
    static int[] dist, parent;

    static List<Integer>[] elevators; // idx = 엘레베이터, element = 각 층
    static List<Integer>[] floors; // idx = 층 , element = 가능한 엘레베이터

    static final int MAX = Integer.MAX_VALUE;

    static class Node implements Comparable<Node> {
        int elevator, dist;

        public Node(int elevator, int dist) {
            this.elevator = elevator;
            this.dist = dist;
        }


        @Override
        public int compareTo(Node o) {
            return dist - o.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());
        M = Integer.parseInt(st.nextToken());

        elevators = new List[M + 1];
        floors = new List[N + 1];

        dist = new int[M + 1];
        parent = new int[M + 1];
        Arrays.fill(dist, MAX);

        for (int i = 0; i < M + 1; i++) {
            elevators[i] = new ArrayList<>();
        }

        for (int i = 0; i < N + 1; i++) {
            floors[i] = new ArrayList<>();
        }

        for (int i = 1; i <= M; i++) {
            st = new StringTokenizer(br.readLine());
            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());

            // 각 층 및 엘레베이터 추가
            for (int j = x; j <= N; j+= y) {
                elevators[i].add(j);
                floors[j].add(i);
            }
        }

        st = new StringTokenizer(br.readLine());
        int A = Integer.parseInt(st.nextToken());
        int B = Integer.parseInt(st.nextToken());

        dijkstra(A, B);



    }

    private static void dijkstra(int start, int end) {
        PriorityQueue<Node> pq = new PriorityQueue<>();

        // 시작 위치가 있는 엘레베이터는 바로 현재 층이므로 거리가 1
        for (int elevator : floors[start]) {
            pq.offer(new Node(elevator, 1));
            parent[elevator] = -1; // -1로 시작지점을 표시
            dist[elevator] = 1;
        }


        while (!pq.isEmpty()) {
            Node current = pq.poll();
            if (dist[current.elevator] < current.dist) continue;

            // 현재 엘레베티어에 있는 모든 층을 꺼낸다.
            for (int floor : elevators[current.elevator]) {

                // 꺼낸 각각의 층이 탈 수 있는 모든 엘레베이터를 꺼낸다.
                for (int i = 0; i < floors[floor].size(); i++) {
                    int elevator = floors[floor].get(i);
                    // 해당 엘레베이터로 가는 비용이 현재 엘베를 갈아타고 가는게 비용이 더 적다면 갱신
                    if (dist[elevator] > current.dist + 1) {
                        dist[elevator] = current.dist + 1;
                        parent[elevator] = current.elevator;
                        pq.offer(new Node(elevator, dist[elevator]));
                    }

                }
            }
        }

        int min = MAX;
        int minElevator = 0;
        for (int elevator : floors[end]) {
            if (dist[elevator] < min) {
                min = dist[elevator];
                minElevator = elevator;
            }
        }

        if (min == MAX) {
            System.out.println(-1);

        }else {
            System.out.println(min);

            Stack<Integer> stack = new Stack<>();
            int cur = minElevator;
            while (cur != -1) {
                stack.push(cur);
                cur = parent[cur];
            }

            while (!stack.isEmpty()) {
                System.out.println(stack.pop());
            }
        }
    }

}

🔅 문제 풀이 [BFS]

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

public class Main {

    static int n, m;
    static List<Integer>[] floors;
    static List<Integer>[] elevators;
    static boolean[] visited;
    static int[] parent;
    static int[] 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());
        m = Integer.parseInt(st.nextToken());


        elevators = new List[m + 1];
        floors = new List[n + 1];
        visited = new boolean[m + 1];

        parent = new int[m + 1];

        for (int i = 0; i <= m; i++) {
            elevators[i] = new ArrayList<>();
        }
        for (int i = 0; i <= n; i++) {
            floors[i] = new ArrayList<>();
        }


        for (int i = 1; i <= m; i++) {
            st = new StringTokenizer(br.readLine());
            int start = Integer.parseInt(st.nextToken());
            int plus = Integer.parseInt(st.nextToken());

            for (int j = start; j <= n; j += plus) {
                elevators[i].add(j);
                floors[j].add(i);
            }
        }

        st = new StringTokenizer(br.readLine());
        int A = Integer.parseInt(st.nextToken());
        int B = Integer.parseInt(st.nextToken());

        dist = new int[m + 1];
        Arrays.fill(dist, Integer.MAX_VALUE);

        int answer = bfs(A, B);

        if (answer == -1) {
            System.out.println(answer);

        } else {
            StringBuilder sb = new StringBuilder();
            sb.append(answer).append("\n");

            int min = Integer.MAX_VALUE;
            int minElevator = 0;
            for (Integer i : floors[B]) {
                if (min > dist[i]) {
                    min = dist[i];
                    minElevator = i;
                }

            }
            int cur = minElevator;
            Stack<Integer> stack = new Stack<>();

            while (cur != -1) {
                stack.push(cur);
                cur = parent[cur];
            }

            while (!stack.isEmpty()) {
                sb.append(stack.pop()).append("\n");
            }


            System.out.print(sb.toString());
        }
    }

    // floors : 각 층에 있는 엘레베이터 리스트
    // elevaotrs : 각 엘레베이터에 있는 층들

    private static int bfs(int start, int end) {
        Queue<Integer> q = new LinkedList<>();

        for (int elevator : floors[start]) {
            q.add(elevator);
            dist[elevator] = 1;
            parent[elevator] = -1;
            visited[elevator] = true;
        }

        while (!q.isEmpty()) {
            int cur = q.poll();
            for (int floor : elevators[cur]) {
                if (floor == end) {
                    return dist[cur];
                }


                for (int i = 0; i < floors[floor].size(); i++) {
                    int nextElevator = floors[floor].get(i);
                    if (!visited[nextElevator]) {
                        visited[nextElevator] = true;
                        dist[nextElevator] = dist[cur] + 1;
                        parent[nextElevator] = cur;

                        q.add(nextElevator);
                    }

                }
            }
        }

        return -1;
    }






}

❗ 오답노트 / 필요한 지식

  1.  컬렉션객체는 for-each사용시 iterator를 사용한다는것을 다시한번 리마인드하게되었다.