본문 바로가기
algorithm/Code Tree

[Code Tree] 코드트리 빵(Java)

by eo_neunal 2023. 4. 3.

문제

https://www.codetree.ai/training-field/frequent-problems?page=3&pageSize=20

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai

풀이

[자료 구조]

- int[][] DELTAS: 사방 이동 좌표

- PriorityQueue<int[]> NEXT_MOVES: 사람이 편의점을 향해 가는 다음 위치

    - 이동 수 기준 오름차순 정렬

- PriorityQueue<int[]> MOVES: 편의점에서 베이스캠프까지의 움직임

    - 이동 수 기준 오름차순 정렬 > 이동 수 같으면 행 기준 오름차순 정렬 > 행 같으면 열 기준 오름차순 정렬

- int[][] map: 베이스 캠프의 정보와 베이스 캠프 및 편의점의 방문 여부

    - 베이스 캠프 = 1

    - 더이상 방문 불가 지역: =음수(해당 지역에 방문한 사람 번호의 음수)

- int[][] convenienceStores: 편의점의 위치

    - convenienceStores[i] = i번재 사람이 가고자 하는 편의점 좌표

- boolean[][] isVisited: 편의점에서 베이스캠프까지의 최단 경로를 구하기 위한 방문 여부

- PriorityQueue<int[]>[] people: 사람들의 이동 위치

    - 이동 수 기준 오름차순 정렬

 

[풀이]

- m명의 사람이 모두 편의점에 도착할 때까지 아래 과정 반복한다.

    1. 편의점을 향해 이동

        - people의 각 요소를 탐색하며, 이동 가능하면(people[i]가 비어있지 않으면) 사방 중 범위 내에 있으면서 방문 가능한(map[x][y] >= 0) 위치를 NEXT_MOVES에 추가

        - 사방 탐색 중 편의점에 도착하면 arrive를 증가시키고, map[x][y]을 -i로 초기화. 더이상 사람이 이동을 하면 안되므로 people[i]와 NEXT_MOVES를 모두 초기화시킨다.

        - 편의점에 도착하지 못하면 NEXT_MOVES를 people[i]에 모두 추가한 후 초기화시킨다.

    2. time <= m이면, 베이스캠프로 이동

        - time번째 사람이 가고자 하는 편의점의 x, y 좌표와 이동 수 0을 원소로 갖는 int[]를 MOVES에 삽입한다.

        - 방문체크를 위한 isVisited를 false로 초기화시킨다.

        - 베이스 캠프에 도착할 때까지 범위 내에 있으면서(x >= 0 && x < n && y >= 0 && y < n) 한 번도 방문하지 않았고(!isVisited[x][y]), 방문이 가능한(map[x][y] >= 0) 곳을 MOVES에 추가하고, 방문 처리해준다.

        - 베이스 캠프에 도착하면 map[x][y]를 -i로 초기화 시키고, 현재 위치의 x, y 좌표와 이동 수 0을 원소로 갖는 int[]를 people[i]에 삽입하고, MOVES를 초기화시킨다.

- m명이 모두 도착하면 time을 출력한다.

소스 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {

    private static final int[][] DELTAS = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}};
    private static final int EMPTY = 0;
    private static final int BASECAMP = 1;
    private static final int MOVE = 2;
    private static final PriorityQueue<int[]> NEXT_MOVES = new PriorityQueue<>(Comparator.comparing(person -> person[MOVE]));
    private static final PriorityQueue<int[]> MOVES = new PriorityQueue<>((p1, p2) -> {
        if (p1[MOVE] == p2[MOVE]) {
            if (p1[0] == p2[0]) {
                return p1[1] - p2[1];
            }
            return p1[0] - p2[0];
        }
        return p1[MOVE] - p2[MOVE];
    });

    private static int[][] map;
    private static int[][] convenienceStores;
    private static boolean[][] isVisited;
    private static PriorityQueue<int[]>[] people;
    private static int n;
    private static int m;
    private static int arrive;

    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());
        n = Integer.parseInt(stringTokenizer.nextToken());
        m = Integer.parseInt(stringTokenizer.nextToken());
        map = new int[n][n];
        isVisited = new boolean[n][n];
        for (int i = 0; i < n; i++) {
            stringTokenizer = new StringTokenizer(bufferedReader.readLine());
            for (int j = 0; j < n; j++) {
                map[i][j] = Integer.parseInt(stringTokenizer.nextToken());
            }
        }
        convenienceStores = new int[m + 1][2];
        people = new PriorityQueue[m + 1];
        for (int i = 1; i <= m; i++) {
            stringTokenizer = new StringTokenizer(bufferedReader.readLine());
            convenienceStores[i][0] = Integer.parseInt(stringTokenizer.nextToken()) - 1;
            convenienceStores[i][1] = Integer.parseInt(stringTokenizer.nextToken()) - 1;
            people[i] = new PriorityQueue<>(Comparator.comparing(person -> person[MOVE]));
        }
        int time = 0;
        while (arrive < m) {
            time++;
            moveToConvenienceStore();
            if (time <= m) {
                moveToBasecamp(time);
            }
        }
        System.out.println(time);
    }

    private static void moveToConvenienceStore() {
        for (int i = 1; i <= m; i++) {
            while (!people[i].isEmpty()) {
                int[] current = people[i].poll();
                int x = current[0];
                int y = current[1];
                for (int[] delta : DELTAS) {
                    int dx = x + delta[0];
                    int dy = y + delta[1];
                    if (isInRange(dx, dy) && map[dx][dy] >= EMPTY) {
                        if (convenienceStores[i][0] == dx && convenienceStores[i][1] == dy) {
                            arrive++;
                            map[dx][dy] = -i;
                            people[i].clear();
                            NEXT_MOVES.clear();
                            break;
                        }
                        NEXT_MOVES.offer(new int[]{dx, dy, current[MOVE] + 1});
                    }
                }
            }
            people[i].addAll(NEXT_MOVES);
            NEXT_MOVES.clear();
        }
    }

    private static void moveToBasecamp(int time) {
        MOVES.offer(new int[]{convenienceStores[time][0], convenienceStores[time][1], 0});
        for (int i = 0; i < n; i++) {
            Arrays.fill(isVisited[i], false);
        }
        while (!MOVES.isEmpty()) {
            int[] current = MOVES.poll();
            int x = current[0];
            int y = current[1];
            if (map[x][y] == BASECAMP) {
                map[x][y] = -time;
                people[time].offer(new int[]{x, y, 0});
                MOVES.clear();
                return;
            }
            for (int[] delta : DELTAS) {
                int dx = x + delta[0];
                int dy = y + delta[1];
                if (isInRange(dx, dy) && !isVisited[dx][dy] && map[dx][dy] >= EMPTY) {
                    isVisited[dx][dy] = true;
                    MOVES.offer(new int[]{dx, dy, current[MOVE] + 1});
                }
            }
        }
    }

    private static boolean isInRange(int dx, int dy) {
        return dx >= 0 && dx < n && dy >= 0 && dy < n;
    }
}

'algorithm > Code Tree' 카테고리의 다른 글

[Code Tree] 포탑 부수기(Java)  (0) 2023.09.14
[Code Tree] 싸움땅(Java)  (0) 2023.04.06