나의 공부장

백준 14499 주사위 굴리기 [Simulation] 본문

알고리즘/BOJ

백준 14499 주사위 굴리기 [Simulation]

꾸준한나 2020. 4. 28. 21:19

문제 링크: 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개의 줄에 지도에 쓰여 있는 수가 북쪽부터 남쪽으로, 각 줄은 서쪽부터 동쪽 순서대로 주어진다. 주사위를 놓은 칸에 쓰여 있는 수는 항상 0이다. 지도의 각 칸에 쓰여 있는 수는 10을 넘지 않는 자연수 또는 0이다. 마

www.acmicpc.net

문제 풀이

주사위를 표현할 수 있는 2차원 배열 dice를 만들어서 문제를 해결했습니다.

dice[4][3]이라고 배열을 만들고, 평면도를 펼쳤을 때 주사위에 해당하는 부분인 곳은 다음과 같습니다.

 

dice[0][0]dice[0][1]dice[0][2]

dice[1][0]dice[1][1]dice[1][2]

dice[2][0]dice[2][1]dice[2][2]

dice[3][0]dice[3][1]dice[3][2]

이렇게 가정하면, 주사위의 윗면은 dice[3][1]입니다.

 

예제를 하나씩 적어서 굴려보면 다음과 같은 규칙을 찾을 수 있습니다.

 

동쪽으로 주사위를 굴릴 경우,

[1][2] -> [1][1] -> [1][0] ->[3][1] -> [1][2]

 

서쪽으로 주사위를 굴릴 경우,

[1][0] -> [1][1] -> [1][2] ->[3][1] -> [1][0]

 

북쪽으로 주사위를 굴릴 경우,

[0][1] -> [1][1] -> [2][1] ->[3][1] -> [0][1]

 

남쪽으로 주사위를 굴릴 경우,

[0][1] -> [3][1] -> [2][1] ->[1][1] -> [0][1]

 

또, 이동한 칸(지도의 숫자가) 0이면, 주사위의 바닥면에 쓰여 있는 숫자가 지도에 복사됩니다.

만약에 이동한 칸이 0이 아닌 경우이면 지도에 쓰인 숫자가 주사위의 바닥면으로 복사되며, 지도의 숫자는 0으로 해준다는 조건이 있습니다.

 

위의 경우를 다 코드로 작성해서 풀었습니다.

소스 코드
#include <iostream>
#include <queue>
using namespace std;

int dice[4][3]; // 주사위
int a[21][21];  // 지도
int N, M, K;
pair<int, int> now; // 주사위의 현재위치
pair<int, int> direction[4] = { {0,1}, {0,-1}, {-1,0}, {1,0} }; // 동, 서, 북, 남


int main()
{
	//freopen("input.txt", "r", stdin);
	cin >> N >> M >> now.first >> now.second >> K;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
		{
			cin >> a[i][j];
		}
	}

	queue<int> q;
	for (int i = 0; i < K; i++)
	{
		int command;
		cin >> command;
		q.push(command);
	}

	// 명령어에 따라 다음의 내용을 수행한다.
	while (!q.empty())
	{
		int dir = q.front();
		q.pop();

		int cx = now.first;
		int cy = now.second;

		
		if (dir == 1) // 동쪽
		{
			int nx = cx + direction[dir - 1].first;
			int ny = cy + direction[dir - 1].second;
			if (nx >= 0 && ny >= 0 && nx < N && ny < M)
			{
				// 주사위의 위치를 저장
				now = { nx,ny };

				// 주사위 변경
				int temp = dice[3][1];
				dice[3][1] = dice[1][0];
				dice[1][0] = dice[1][1];
				dice[1][1] = dice[1][2];
				dice[1][2] = temp;

				// 이동한 칸이 0이면 주사위의 바닥면에 쓰인 숫자가 지도에 복사
				if (a[nx][ny] == 0) a[nx][ny] = dice[1][1];
				// 0이 아닌 경우에는 지도에 쓰여진 수가 주사위의 바닥 면에 복사
				else
				{
					dice[1][1] = a[nx][ny];
					a[nx][ny] = 0;
				}
				
				// 주사위의 가장 윗면을 출력한다.
				cout << dice[3][1] << '\n';
			}
		}
		else if (dir == 2) // 서쪽
		{
			int nx = cx + direction[dir - 1].first;
			int ny = cy + direction[dir - 1].second;
			if (nx >= 0 && ny >= 0 && nx < N && ny < M)
			{
				now = { nx,ny };
				int temp = dice[3][1];
				dice[3][1] = dice[1][2];
				dice[1][2] = dice[1][1];
				dice[1][1] = dice[1][0];
				dice[1][0] = temp;

				if (a[nx][ny] == 0) a[nx][ny] = dice[1][1];
				else
				{
					dice[1][1] = a[nx][ny];
					a[nx][ny] = 0;
				}

				cout << dice[3][1] << '\n';
			}
		}
		else if (dir == 3) // 북쪽
		{
			int nx = cx + direction[dir - 1].first;
			int ny = cy + direction[dir - 1].second;
			if (nx >= 0 && ny >= 0 && nx < N && ny < M)
			{
				now = { nx,ny };
				int temp = dice[3][1];
				dice[3][1] = dice[2][1];
				dice[2][1] = dice[1][1];
				dice[1][1] = dice[0][1];
				dice[0][1] = temp;

				if (a[nx][ny] == 0) a[nx][ny] = dice[1][1];
				else
				{
					dice[1][1] = a[nx][ny];
					a[nx][ny] = 0;
				}

				cout << dice[3][1] << '\n';
			}
		}
		else if (dir == 4) // 남쪽
		{
			int nx = cx + direction[dir - 1].first;
			int ny = cy + direction[dir - 1].second;
			if (nx >= 0 && ny >= 0 && nx < N && ny < M)
			{
				now = { nx,ny };
				int temp = dice[3][1];
				dice[3][1] = dice[0][1];
				dice[0][1] = dice[1][1];
				dice[1][1] = dice[2][1];
				dice[2][1] = temp;

				if (a[nx][ny] == 0) a[nx][ny] = dice[1][1];
				else
				{
					dice[1][1] = a[nx][ny];
					a[nx][ny] = 0;
				}

				cout << dice[3][1] << '\n';
			}
		}
	}


	return 0;
}