백준 14499 - 주사위 굴리기

5 minute read

문제링크

문제설명

  • 크기가 NxM인 지도의 각 칸에는 정수가 적혀 있다.
  • 주사위를 동서남북으로 굴릴 수 있고, 굴렸을 때 이동한 칸에 쓰여 있는 수가 0이면, 주사위 바닥면에 쓰인 수가 칸에 복사된다. 이동한 칸에 쓰여 있는 수가 0이 아닌 경우 칸에 쓰여 있는 수가 주사위 바닥면으로 복사되고, 칸에 쓰인 수는 0이 된다.
  • 주사위가 놓인 좌표와 이동시키는 명령이 주어졌을 때, 주사위가 이동했을 때마다 주사위 상단에 쓰여 있는 값을 구하라

입력

  • 첫째 줄에 지도의 세로 크기 N, 가로 크기 M, (20 이하 자연수) 그리고 주사위를 놓은 곳의 좌표 x,y 그리고 명령의 개수 K(1000이하 자연수)가 주어진다.
  • 둘째 줄부터 N개의 줄에 지도에 쓰여 있는 수가 행 별로 주어진다.
  • 마지막 줄에는 이동하는 명령이 순서대로 주어진다. 동쪽은 1, 서쪽은 2, 북쪽은 3, 남쪽은 2

문제접근방향

  • 문제에 주어진 주사위 전개도를 배열 인덱스로 사용하고, 해당 인덱스에는 주사위에 적힌 숫자를 담는다. dice[7] 을 선언하면, dice[1]~dice[6]에는 각 주사위 면의 적힌 숫자가 담기고, 밑바닥면은 dice[1], 상단면은 dice[6]이다.
  • 동서북남으로 굴렸을 때, 전개도 상의 위치를 담는 변수를 선언한다. 예를 들어, roll_dice_changed_idx[5][7] 을 선언하면, roll_dice_changed_idx[1][1]~roll_dice_changed_idx[1][6]은 동쪽으로 굴렸을 때 주사위 면 1번~6번에 위치하게 되는 굴리기 전 주사위 인덱스를 의미한다.
  • 바깥으로 이동하는 경우 해당 명령을 무시해야 하므로, 굴렸을 때 좌표를 확인하는 로직이 먼저 필요하다.

구현1

#include <iostream>
#include <vector>
using namespace std;

vector<int> dice(7,0);
int roll_dice_changed_idx[5][7] = {
	{0, 0, 0, 0, 0, 0, 0}, // not used
	{0, 3, 2, 6, 1, 5, 4},
	{0, 4, 2, 1, 6, 5, 3},
	{0, 2, 6, 3, 4, 1, 5},
	{0, 5, 1, 3, 4, 6, 2}
};
//	not used,  동, 서, 북, 남
int dx[5] = { 0, 0, 0, -1, 1 };
int dy[5] = { 0, 1, -1, 0, 0 };


bool check_valid(vector<vector<int>>& map, int xpos, int ypos) {
	int m = map[0].size(); // 열 길이 계산
	int n = map.size(); // 행 길이 계산
	if (xpos >= 0 && xpos < n && ypos >= 0 && ypos < m) 
		return true;
	return false;
}

// 굴리고 난 후 주사위 면 위치를 조정한다.
void set_dice(vector<int>& direction, int cnt_move) {
	int dir = direction[cnt_move];
	vector<int> tmp_dice(7,0);
	for (int i = 1; i < 7; i++) {
		tmp_dice[i] = dice[roll_dice_changed_idx[dir][i]];
	}
	dice = tmp_dice;
}

void move_dice(vector<vector<int>>& map, vector<int>& direction, int x, int y, int cnt_move) {
	int cur_x = x;
	int cur_y = y;
	int val = 0;
	for (int i = 0; i < cnt_move; i++) {
		int next_x = cur_x + dx[direction[i]];
		int next_y = cur_y + dy[direction[i]];
		// 범위를 벗어나는 경우 해당 명령을 무시하고 출력도 하지 않는다.
		if (check_valid(map, next_x, next_y) == false) continue;
		val = map[next_x][next_y]; // 이동한 칸에 적힌 숫자
		set_dice(direction, i);

		// 이동한 칸에 적힌 숫자가 0이면 주사위 바닥면에 적힌 숫자를 칸에 복사
		// 0이 아니면 칸에 있는 숫자를 주사위 바닥면에 복사하고 칸은 0으로 설정
		if (val == 0) {
			map[next_x][next_y] = dice[1];
		}
		else {
			dice[1] = val;
			map[next_x][next_y] = 0;
		}
		cur_x = next_x;
		cur_y = next_y;
		cout << dice[6] << endl;
	}
}

int main()
{
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);
	int n, m, x, y, k;
	cin >> n >> m >> x >> y >> k;

	vector<vector<int>> map(n, vector<int>(m, 0));
	vector<int> direction(k);
	for (int r = 0; r < n; r++) {
		for (int c = 0; c < m; c++) {
			cin >> map[r][c];
		}
	}
	for (int i = 0; i < k; i++)
		cin >> direction[i];

	move_dice(map, direction, x, y, k);
}

구현2

#include <iostream>
#include <vector>
using namespace std;

int changedIndexDice[5][7] = {
    {0, 0, 0, 0, 0, 0, 0},
    {0, 3, 2, 6, 1, 5, 4}, // dir: 1
    {0, 4, 2, 1, 6, 5, 3}, // dir: 2
    {0, 2, 6, 3, 4, 1, 5}, // dir: 3
    {0, 5, 1, 3, 4, 6, 2}, // dir: 4
};

bool CheckValid(int n, int m, int x, int y){
    if(x>=0 && x<n && y>=0 && y<m) return true;
    else return false;
}

bool RollDice(vector<vector<int>>& board, vector<int>& dice, int dir, int x, int y){
    // 범위를 벗어나는 경우 해당 명령 무시
    if(CheckValid(board.size(), board[0].size(), x, y)==false) 
        return false;
    
    vector<int> tmp = dice;
    // dir: 1,2,3,4 -> 동,서,북,남
    for(int i=1; i<=6; i++){
        dice[i] = tmp[changedIndexDice[dir][i]];
    }
    // 주사위 바닥면 복사
    if(board[x][y]==0) 
        board[x][y] = dice[1];
    else{
        dice[1] = board[x][y];
        board[x][y] = 0;
    }
    cout << dice[6] << endl;
    return true;
}

int main()
{
    cin.tie(NULL);
    ios_base::sync_with_stdio(false);

    int N, M, x, y, K;
    cin >> N >> M >> x >> y >> K;

    vector<vector<int>> board(N, vector<int>(M,0));
    vector<int> dice(7,0); // 1~6번 주사위면
    for(int r=0; r<N; r++){
        for(int c=0; c<M; c++)
            cin >> board[r][c];
    }
    int dir, nextX, nextY;
    for(int i=0; i<K; i++){
        cin >> dir;
        if(dir==1){
            nextX = x; nextY = y+1;
        }
        else if(dir==2){
            nextX = x; nextY = y-1;
        }
        else if(dir==3){
            nextX = x-1; nextY = y;
        }
        else if(dir==4){
            nextX = x+1; nextY = y;
        }
        if(RollDice(board, dice, dir, nextX, nextY)){
            x = nextX, y = nextY;
        }
    }
    
    return 0;
}

구현3

#include <iostream>
#include <memory.h>
#include <vector>

#define MAX_N_M 20
#define MAX_DICE 7
#define TOP 1
#define BOTTOM 6
#define MAX_DIR 5
using namespace std;

int N, M;
int board[MAX_N_M][MAX_N_M];
int dicePos[MAX_DIR][MAX_DICE] = {
	{0, 0, 0, 0, 0, 0, 0},
	{0, 4, 2, 1, 6, 5, 3},
	{0, 3, 2, 6, 1, 5, 4},
	{0, 5, 1, 3, 4, 6, 2},
	{0, 2, 6, 3, 4, 1, 5}
};
int dx[5] = { 0, 0, 0, -1, 1 };
int dy[5] = { 0, 1, -1, 0, 0 };

void moveDice(vector<int>& diceStatus, int xpos, int ypos, int dir) 
{
	vector<int> tmpDiceStatus = diceStatus;
	for (int i = 1; i < MAX_DICE; i++) {
		diceStatus[i] = tmpDiceStatus[dicePos[dir][i]];
	}
	if (board[xpos][ypos] == 0) board[xpos][ypos] = diceStatus[BOTTOM];
	else {
		diceStatus[BOTTOM] = board[xpos][ypos];
		board[xpos][ypos] = 0;
	}

	cout << diceStatus[TOP] << "\n";
}


int main()
{
	cin.tie(NULL);
	ios_base::sync_with_stdio(false);

	int xpos, ypos, K;
	cin >> N >> M >> xpos >> ypos >> K;
	memset(board, 0, sizeof(board));
	for (int r = 0; r < N; r++) {
		for (int c = 0; c < M; c++) {
			cin >> board[r][c];
		}
	}

	vector<int> diceStatus(MAX_DICE, 0);
	int dir, nx = xpos, ny = ypos;
	for (int i = 0; i < K; i++) {
		cin >> dir;
		nx += dx[dir];
		ny += dy[dir];
		if (nx < 0 || nx >= N || ny < 0 || ny >= M) {
			nx -= dx[dir];
			ny -= dy[dir];
			continue;
		}
		moveDice(diceStatus, nx, ny, dir);
	}
}

Leave a comment