본문 바로가기

~2023

[Python] 백준 14499번 문제, 주사위 굴리기

728x90
반응형

<문제 링크>

 

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

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지도

www.acmicpc.net

 


<풀이>

 

시뮬레이션 문제를 풀 때는 머리로 생각만 하기 보다는 그림을 직접 그려가며 풀면 해답에 쉽게 다가갈 수 있는 것 같다.

그림 1.

우선 문제에서 주사위 전개도를 그림 1과 같이 정의를 했지만, 직접 그려서 풀다 보면 저 형태가 불편하다.

그림 1은 윗면을 기준으로 풀어진 전개도이지만, 나는 바닥면을 기준으로 풀어진 전개도를 가지고 문제를 풀었다.

 

<예제 2 시뮬레이션>

board에서 파란 원은 board[dx][dy],

오른쪽 전개도에서 파란 원은 바닥면, 붉은 원은 윗면을 뜻함

(*이미지를 먼저 보여준 후에 해당 이미지에 대한 설명을 이미지 아래 글에 덧붙이겠다.)

1, 2, 3

주사위 dice의 초기값은 모든 면이 0이다.

(1, 1)에서 (1, 2)로 움직였을 때 전개도를 보면 단순히 바닥면에 5를 넣은 것 같지만, 그렇지 않다.

moving의 파라미터인 order에 따라 값들의 자리를 바꾼 후에 dice.bottom에 board[dx][dy] 값을 삽입해야 한다.

2번째 반복문처럼 위아래로 이동하는거에 대한 로직은 쉽게 생각해냈지만, 1과 3과 같이 좌우로 이동하는 경우에 어떤 것들끼리 바꿔야 하는지 생각만 하다가 그림을 그려 보니 한 번에 이해가 됐다.

4, 5, 6

3 -> 4로 바뀌는 것을 보면 front(0)과 back(5)가 바뀌지 않는 걸 볼 수 있다.

그렇기 때문에 서쪽으로 이동 시 앞뒤는 그대로 유지시키고 좌우와 위아래만 바꾸면 된다는 걸 알 수 있다.

서쪽으로 이동 시 왼쪽면이 바닥면이 되며, 바닥면은 새로운 바닥면의 오른쪽 면이 된다.

주사위 값들은 한 세트(위아래, 좌우, 앞뒤)로 움직이기 때문에 이것들 이용해 자리값들을 교체해주면 된다.

동쪽도 서쪽과 마찬가지로 이동 시 앞뒤는 바뀌지 않는다.

또한, 북 또는 남으로 이동 시 좌우는 변하지 않은 채 주사위 자리를 하나씩 올리거나 내리면 된다.

7, 8, 9

문제 조건으로 board[dx][dy]가 0이 아닌 경우에는 바닥면에 board값이 복사가 되며 board는 0이 된다.

board 값이 0이라면 dice 바닥면의 값을 복사해주기만 하면 된다.

 


<코드>

N, M, x, y, K: 세로 크기, 가로 크기, 좌표 x, 좌표 y, 명령 개수

board[][]: (N, M) 크기의 보드판(맵)

dice: 주사위 정보를 담고 있는 주사위 객체

move[]: 동서남북 이동 방향을 저장해둔 리스트

i, j: 첫 시작 좌표 (i, j) (= x, y)

dx, dy: 이동한 좌표값

Dice.moving(): order에 알맞은 방향으로 주사위를 이동 후, 바닥을 기준으로 필드 멤버 변수들 수정해주는 메소드


import sys


class Dice:
    def __init__(self):
        self.left = 0
        self.right = 0
        self.top = 0
        self.bottom = 0
        self.front = 0
        self.back = 0

    '''
        map_value: 이동한 후에 지도 값
        operator: 동(1), 서(2), 북(3), 남(4)
    '''
    def moving(self, order):
        if order == 1:
            left, right, top, bottom = self.bottom, self.top, self.left, self.right
            self.left, self.right, self.top, self.bottom = left, right, top, bottom
        elif order == 2:
            left, right, top, bottom = self.top, self.bottom, self.right, self.left
            self.left, self.right, self.top, self.bottom = left, right, top, bottom
        elif order == 3:
            front, back, top, bottom = self.top, self.bottom, self.back, self.front
            self.front, self.back, self.top, self.bottom = front, back, top, bottom
        else:
            front, back, top, bottom = self.bottom, self.top, self.front, self.back
            self.front, self.back, self.top, self.bottom = front, back, top, bottom


if __name__ == "__main__":
    N, M, x, y, K = map(int, sys.stdin.readline().rstrip().split())
    board = [[] for _ in range(N)]
    dice = Dice()
    move = [(0, 1), (0, -1), (-1, 0), (1, 0)]

    # create board(map)
    for i in range(N):
        board[i] = list(map(int, sys.stdin.readline().rstrip().split()))

    # position (i, j)
    i, j = x, y
    # processing order
    orders = list(map(int, sys.stdin.readline().rstrip().split()))
    for order in orders:
        dx, dy = i + move[order - 1][0], j + move[order - 1][1] # 이동한 후에 좌표값
        if (0 <= dx < N) and (0 <= dy < M):
            i, j = dx, dy # 이동한 좌표값이 범위 내라면 좌표값 저장
            if board[dx][dy] == 0: # 현재 보드 값이 0이면 bottom을 board[dx][dy]에 복사
                dice.moving(order)
                print(dice.top)
                board[dx][dy] = dice.bottom
            else: # 현재 보드 값이 0이 아니면, bottom에 현재 보드 값 복사 후 보드 값 0으로 만들기
                dice.moving(order)
                print(dice.top)
                dice.bottom = board[dx][dy]
                board[dx][dy] = 0

 

 

 

 

 

 
728x90
반응형