문제 링크 : 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. 좌표는 (x,y)로 표시한다.

2. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다.

3. 움직인 칸이 지도의 범위 밖일 경우, 움직이지 않고 아무것도 출력하지 않는다.

 

문제 풀이는 다음과 같다.

1. 주사위의 전개도에 값을 넣을 배열은 편의상 1~6을 모두 사용하기 위해 사이즈를 7로 잡는다. 

또한 움직임의 범위를 나타내는 4방위의 값은 문제에서 언급한 그대로 동 -> 서 -> 북 -> 남으로 저장해준다.

dice[7] = {0,}, mx[] = {0,0,-1,1}, my[] = {1,-1,0,0},

2. 지도의 값을 입력받고 주사위의 값 만큼 움직임을 진행한다.

3. 아래는 주사위의 값만큼 움직이는 go함수의 일부이다.

void go(int dir){
    dir--;
    x+=mx[dir];
    y+=my[dir];
    if(x<0||x>=n||y<0||y>=m){
        x-=mx[dir];
        y-=my[dir];
        return;
    }
    dir++;

움직임의 값을 저장한 배열은 0~3까지 값이 저장되어 있으므로, dir(방향값)에 -1을 해줘서 움직임을 저장해준다. 

이때 지도의 범위를 초과했으면 원래값으로 되돌린뒤 바로 return해준다.

그렇지 않을 경우, 주사위의 방향을 판단하기 위해 dir에 +1을 해주어 원래대로 되돌려준다.

 

4. 아래는 동서남북의 방향에 따라 주사위의 배치도가 변하는 로직이다. 

이 부분은 이해가 안될 경우, 직접 전개도의 그림을 그려서 비교해주면 이해하기 쉽다.

    if(dir==1){ // 동
        temp = dice[1];
        dice[1] = dice[4];
        dice[4] = dice[6];
        dice[6] = dice[3];
        dice[3] = temp;
    }
    else if(dir==2){ // 서
        temp = dice[1];
        dice[1] = dice[3];
        dice[3] = dice[6];
        dice[6] = dice[4];
        dice[4] = temp;
    }
    else if(dir==3){ // 북
        temp = dice[1];
        dice[1] = dice[5];
        dice[5] = dice[6];
        dice[6] = dice[2];
        dice[2] = temp;
    }
    else{ // 남
        temp = dice[1];
        dice[1] = dice[2];
        dice[2] = dice[6];
        dice[6] = dice[5];
        dice[5] = temp;
    }

이해하기 쉽게 설명을 덧붙이자면, 문제에서 언급한 주사위의 전개도를 기준으로 '그대로' 활용해야한다는 점이다.

 

5. 움직인 방향의 지도값이 0일 경우, 주사위의 바닥면에 쓰인 숫자가 지도에 복사된다.

고로 dice[6]에 쓰여있는 값을 지도 arr[x][y]에 복사해주면 된다.

반대로 움직인 방향의 지도값이 0이 아닐 경우, 해당 값을 주사위의 바닥에 복사해주고 지도의 값은 0으로 바꿔주면 된다.

고로 dice[6]에는 arr[x][y]의 값을 복사해주고 arr[x][y]는 0으로 저장해준다.

    if(arr[x][y]==0) arr[x][y] = dice[6];
    else {dice[6] = arr[x][y]; arr[x][y] = 0;}

 

6. 마지막으로 주사위의 윗면에 있는 값을 출력해줘야하므로, dice[1]의 값을 출력한다.

 

#include <iostream>
#include <vector>
#include <algorithm>
#define MAX 20
using namespace std;

int n,m,x,y,k,arr[MAX][MAX], dice[7] = {0,}, mx[] = {0,0,-1,1}, my[] = {1,-1,0,0}, temp; // x - y가 기존이랑 반대!

void go(int dir){
    dir--;
    x+=mx[dir];
    y+=my[dir];
    if(x<0||x>=n||y<0||y>=m){
        x-=mx[dir];
        y-=my[dir];
        return;
    }
    dir++;
    if(dir==1){ // 동
        temp = dice[1];
        dice[1] = dice[4];
        dice[4] = dice[6];
        dice[6] = dice[3];
        dice[3] = temp;
    }
    else if(dir==2){ // 서
        temp = dice[1];
        dice[1] = dice[3];
        dice[3] = dice[6];
        dice[6] = dice[4];
        dice[4] = temp;
    }
    else if(dir==3){ // 북
        temp = dice[1];
        dice[1] = dice[5];
        dice[5] = dice[6];
        dice[6] = dice[2];
        dice[2] = temp;
    }
    else{ // 남
        temp = dice[1];
        dice[1] = dice[2];
        dice[2] = dice[6];
        dice[6] = dice[5];
        dice[5] = temp;
    }
    if(arr[x][y]==0) arr[x][y] = dice[6];
    else {dice[6] = arr[x][y]; arr[x][y] = 0;}
    cout << dice[1] << "\n";
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
    cin >> n >> m >> x >> y >> k;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++) cin >> arr[i][j];
    }
    vector<int> v(k);
    for(int i=0; i<k; i++) cin >> v[i];
    for(int i=0; i<k; i++){
        go(v[i]);
    }
    return 0;
}