백준 14499번 - 주사위 굴리기

황제연·2025년 1월 14일
0

알고리즘

목록 보기
153/169
post-thumbnail

문제 탐색하기

입력 자료 정리

  1. n은 지도의 세로 크기, m은 지도의 가로 크기다.
  2. x는 주사위를 처음 놓는 y좌표, y는 주사위를 처음 놓는 x좌표다
  3. 그리고 이어서 오는 k는 명령의 개수다
  4. 이후 들어오는 n x m개의 값은 각 좌표의 바닥면 값이다
  5. 마지막으로 들어오는 k개의 입력값은 주사위의 이동방향에 대한 값이다
    1은 동쪽, 2는 서쪽, 3은 북쪽, 4는 남쪽을 의미한다

해결방법 추론

  1. 입력값도 작고, 주어진 문제 형태를 보면 조건에 맞춰서 구현하는 문제다
  2. 각 명령어마다 3가지 조건에 맞춰서 설계하면 정답을 구할 수 있을 것이다!
  3. 또한 이 문제는 주사위가 이동할 때마다 조건에 맞춰서 변화하기 때문에,
    현재 위치와 주사위 면의 상태를 관리해야한다.
    해당 문제는 별도의 클래스를 설계한다음 인스턴스로 관리하면 될 것이다
  4. 3가지 조건은 순서에 맞게 설계해야한다. 먼저 주사위가 이동하는 것이 첫번쨰 순서이며,
    주사위면의 회전이 두번째고 바닥면과 주사위 바닥면을 비교하여 값을 변경하는 것이 세번째다
  5. 이 순서에 맞춰서 설계한다면 정답을 구할 수 있을 것이다!

시간복잡도 계산

  1. 시간복잡도는 k의 입력값이 가장 크기 때문에 k의 연산만 고려한다
  2. 따라서 시간복잡도는 O(k)가 되고, k의 최대 입력값은 1000이므로 시간제한 안에 문제를 해결할 수 있다

코드 설계하기

입력값 상태 관리

  1. 각 입력값들은 int형 변수에 관리한다
  2. nxm크기의 2차원 int형 배열을 선언해서 지도의 각 값을 관리한다
  3. k만큼 들어오는 순서는 int형 변수로 받는다.
  4. 설계한 구현 코드의 결과를 int형 변수 a로 받는다. 이 값에 따라서 출력할지 여부를 결정할 것이다
    만약 1이면 출력하고 0이면 출력하지 않는다

주사위 상태관리

  1. 주사위의 상태를 관리할 Dice 클래스를 별도로 구현했다
  2. 각 필드는 주사위의 현재 y좌표, x좌표, 그리고 6개의 면에 들어간 숫자를 의미한다

구현 코드 설계

  1. 아래 로직을 모두 통과하면 1을 리턴한다

이동 로직 설계

  1. 이동 로직은 4가지 방향에 따라 다르게 이동해야한다. 1은 동쪽, 2는 서쪽, 3은 북쪽, 4는 남쪽이다
  2. 동쪽은 x를 늘리고, 서쪽은 x를 줄인다. 북쪽은 y를 줄이고, 남쪽은 y를 늘린다
  3. 줄일때는 그 값이 0이상인지 확인하고 늘릴때는 n이나 m 미만인지 확인한다.
    범위안에 포함되는 경우만 주사위의 현재 좌표를 증감한다.
  4. 만약 범위안에 포함되지 않는 경우 바로 0을 리턴한다

주사위면 변경 로직 설계

  1. 이어서 이동방향에 따라 주사위면의 값을 회전시키는 로직이다
  2. 동쪽으로 이동할 경우, 1,4번 면은 고정되고 나머지 면은 다음과 같이 변동한다
    3 -> 0 -> 2 -> 5 -> 3
  3. 주사위 인스턴스의 값만으로 구현하면, 이전에 덮힌 값으로 변경되기 때문에 별도의 배열을 클론해서 활용한다
  4. 서쪽으로 이동할 경우, 똑같이 1,4번 면은 고정되고 나머지 면은 다음과 같이 변동한다
    2 -> 0 -> 3 -> 5 -> 2
  5. 북쪽으로 이동할 경우, 2,3번 면은 고정되고 나머지 면은 다음과 같이 변동한다
    4 -> 0 -> 1 -> 5 -> 4
  6. 남쪽으로 이동할 경우 똑같이 2,3번 면은 고정되고 나머지 면은 다음과 같이 변동한다
    1 -> 0 -> 4 -> 5 -> 1

주사위면 or 바닥면 변경로직 설계

  1. 이번에는 지도의 바닥면의 값에 따라 주사위의 바닥면이나 지도의 바닥면이 변경되는 로직이다
  2. 지도의 바닥면이 0이면, 주사위의 바닥면인 5번 면을 지도 바닥면에 넣는다
  3. 만약 아닐 경우, 주사위의 바닥면에 지도의 바닥면을 넣고 지도의 바닥면은 0으로 초기화한다

출력값 설계

  1. 위 구현값의 리턴 결과가 1인 경우, 주사위의 위쪽면인 0번면을 출력하면 정답이 된다.

정답 코드

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


class Dice{
    int nowY;
    int nowX;
    int[] diceNum;
    Dice(int nowY, int nowX){
        this.nowY = nowY;
        this.nowX = nowX;
        diceNum = new int[6];
    }
}


public class Main {


    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 = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int startY = Integer.parseInt(st.nextToken());
        int startX = Integer.parseInt(st.nextToken());
        int k = Integer.parseInt(st.nextToken());
        int[][] arr = new int[n][m];
        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < m; j++) {
                arr[i][j] = Integer.parseInt(st.nextToken());
            }
        }
        st = new StringTokenizer(br.readLine());
        Dice dice = new Dice(startY, startX);
        for (int i = 0; i < k; i++) {
            int order = Integer.parseInt(st.nextToken());
            int a = dir(order, dice, n, m, arr);
            if(a == 1){
                bw.write(dice.diceNum[0]+"\n");
            }
        }


        br.close();
        bw.close();
    }

    private static int dir(int d, Dice dice, int n, int m, int[][] arr){
        switch (d){
            case 1:
                if(dice.nowX + 1 < m){
                    dice.nowX++;
                }else{
                    return 0;
                }
                rotates(dice, d, n, m);
                solve(dice, arr, arr[dice.nowY][dice.nowX]);
                break;
            case 2:
                if(dice.nowX - 1 >= 0){
                    dice.nowX--;
                }else{
                    return 0;
                }
                rotates(dice, d, n, m);

                solve(dice, arr, arr[dice.nowY][dice.nowX]);
                break;
            case 3:
                if(dice.nowY - 1 >= 0){
                    dice.nowY--;
                }else{
                    return 0;
                }
                rotates(dice, d, n, m);
                solve(dice, arr, arr[dice.nowY][dice.nowX]);
                break;
            case 4:
                if(dice.nowY + 1 < n){
                    dice.nowY++;
                }else{
                    return 0;
                }
                rotates(dice, d, n, m);
                solve(dice, arr, arr[dice.nowY][dice.nowX]);
                break;
        }
        return 1;
    }

    private static void rotates(Dice dice, int d, int n, int m) {
        int[] tmp = dice.diceNum.clone();
        switch (d){
            case 1:
                dice.diceNum[0] = tmp[3];
                dice.diceNum[3] = tmp[5];
                dice.diceNum[5] = tmp[2];
                dice.diceNum[2] = tmp[0];
                break;
            case 2:
                dice.diceNum[0] = tmp[2];
                dice.diceNum[3] = tmp[0];
                dice.diceNum[5] = tmp[3];
                dice.diceNum[2] = tmp[5];
                break;
            case 3:
                dice.diceNum[0] = tmp[4];
                dice.diceNum[1] = tmp[0];
                dice.diceNum[5] = tmp[1];
                dice.diceNum[4] = tmp[5];
                break;
            case 4:
                dice.diceNum[0] = tmp[1];
                dice.diceNum[4] = tmp[0];
                dice.diceNum[5] = tmp[4];
                dice.diceNum[1] = tmp[5];
                break;
        }
    }

    private static void solve(Dice dice, int[][] arr, int now){
        switch (now){
            case 0:
                arr[dice.nowY][dice.nowX] = dice.diceNum[5];
                break;
            default:
                dice.diceNum[5] = arr[dice.nowY][dice.nowX];
                arr[dice.nowY][dice.nowX] = 0;
        }
    }

}

문제 링크

14499번 - 주사위 굴리기

profile
Software Developer

0개의 댓글