스터디/알고리즘 문제풀이

[C++] 백준 14499번 - 주사위 굴리기

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

 

 

처음에 문제를 봤을 때 이해가 한 번에 가지 않아 조금 당황했지만 문제를 이해하고 나면 크게 어렵지는 않은 전형적인 시뮬레이션 문제입니다.

 

크기가 N * M인 지도가 주어지고, 지도의 각각 칸에 숫자가 쓰여있습니다. 주사위가 처음 놓이는 위치가 주어지고, 해당 위치는 지도에 0이 쓰여있습니다. 주사위는 각 면이 0으로 초기화되어있습니다. (문제에서 주사위 전개도를 보여줄 때 주사위에 숫자가 쓰여있다고 착각해 처음 이해할 때 시간이 조금 걸렸습니다.)

 

k번에 걸쳐 주사위를 이동시키는 명령이 입력됩니다. 주사위는 지도 위에서 동, 서, 남, 북으로 굴려지며 주사위가 굴러갈 때마다 주사위의 각 면이 바라보는 방향이 바뀝니다. 이때 이동한 위치의 지도에 쓰여있는 수가 0이라면 주사위의 바닥면에 쓰여있는 숫자를 지도에 적고, 0이 아니라면 주사위의 바닥면에 지도에 쓰여있는 숫자를 적은 뒤 지도에 쓰여있던 수는 0으로 바뀝니다. 단 주사위가 지도의 바깥으로 이동한다면 해당 명령은 무시하고 출력도 하지 않습니다.

 

문제를 이해한 후에는 다른 특이사항 없이 주사위의 각 6개의 면이 네 방향으로 굴려질때 바라보는 방향이 어떻게 바뀌는가만 고려하면 됩니다.

 

vector<int>를 하나 사용해서 크기를 6으로 초기화합니다. 0~5의 인덱스에 주사위의 각 면이 바라보는 방향을 미리 지정합니다. 

vector<int> dice(6); //{0 : 위, 1 : 아래, 2 : 상(북), 3 : 하(남), 4 : 좌(서), 5 : 우(동)}

전역변수로 선언해 초기값은 0이 저장됩니다. (문제에서 가장 처음에 주사위에는 모든 면에 0이 적혀 있다고 명시합니다)

 

동, 서, 남, 북 방향으로 주사위를 굴릴때마다 주사위의 각 면이 보고 있는 방향을 이전 주사위의 상태를 저장하는 tmp변수인덱스를 변경해 바꾸어줍니다.

 

예를 들어, 명령이 1로 입력되었을 때(동쪽으로 주사위 이동) 

상(북), 하(남) 방향을 향하는 주사위의 면은 방향이 바뀌지 않고

왼(서)쪽를 보고 있던 면은 위쪽으로, // dice[0] = tmp[4];

오른(동)쪽을 보고있던 면은 아래쪽으로, // dice[1] = tmp[5];

아래쪽을 보고있던 면은 왼(서)쪽으로, // dice[4] = tmp[1];

위쪽을 보고있던 면은 오른(동)쪽으로 // dice[5] = tmp[0];

방향이 바뀝니다.

 

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

int n, m, x, y, k;
int board[22][22];
vector<int> dice(6); //(위, 아래, 상, 하, 좌, 우)

bool moveXY(int order)
{
	int nx = x;
	int ny = y;
	if (order == 1)	//동
		ny++;
	else if (order == 2)	//서
		ny--;
	else if (order == 3)	//북
		nx--;
	else
		nx++;	//남

	if (nx < 0 || nx >= n || ny < 0 || ny >= m) return false;
	else
	{
		x = nx;
		y = ny;
		return true;
	}
}

void roll(int order)
{
	vector<int> tmp = dice;

	if (order == 1)	//동
	{
		dice[0] = tmp[4];	//좌 -> 위
		dice[1] = tmp[5];	//우 -> 아래
		dice[4] = tmp[1];	//아래 -> 좌
		dice[5] = tmp[0];	//위 -> 우
	}
	else if (order == 2)	//서
	{
		dice[0] = tmp[5];
		dice[1] = tmp[4];
		dice[4] = tmp[0];
		dice[5] = tmp[1];
	}
	else if (order == 3)	//북
	{
		dice[0] = tmp[3];
		dice[1] = tmp[2];
		dice[2] = tmp[0];
		dice[3] = tmp[1];
	}
	else
	{						//남
		dice[0] = tmp[2];
		dice[1] = tmp[3];
		dice[2] = tmp[1];
		dice[3] = tmp[0];
	}
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m >> x >> y >> k;

	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> board[i][j];
		}
	}

	int order;
	while (k--)
	{
		cin >> order;

		//범위 검사 및 좌표 이동
		if (!moveXY(order)) continue;
		
		//주사위 굴리기
		roll(order);

		if (board[x][y])	//0이 아니라면
		{
			dice[1] = board[x][y];	//칸의 쓰여있는 수가 주사위 바닥면(1)으로 복사
			board[x][y] = 0;		//칸의 수는 0
		}
		else
							//0이라면
		{
			board[x][y] = dice[1];	//칸에 주사위의 바닥면 수 쓰기
		}

		cout << dice[0]<<"\n";		//주사위의 상단에 쓰여있는 수 출력
	}

	return 0;
}