191009 백준 알고리즘 문제풀기

|

[14499] 주사위 굴리기

  • 난이도: 하
    • 시뮬레이션 문제로, 푸는데 총 1시간 반 소요됨.
      • 문제 이해하는데 40분, 구현하는데 30분 미만, 디버깅에 30분 걸린 듯 하다.
    • 어려운 문제는 아니였지만, 시뮬레이션의 조건을 잘못 파악하고 실수를 해서 40분이상을 날려먹었다.
      • 조건을 하나 잘못 이해해서 시간을 많이 날려먹었다.
      • 조건을 정확하게 파악하고 정리해두는것이 제일 중요한듯하다.
    • 제일 관건이 되는것은 주사위를 굴리는것 정도로 매우 쉬운 난이도였다.
      • 각각 주사위를 오른쪽, 왼쪽, 위, 아래로 굴릴 때의 case를 분류하고, 이에 맞게 동작하게 하면 됐다.
    • 또한, 행/렬 실수로 시간을 또 날려먹었다.
      • 제일 자주하고 반복되는 실수로.. 꼭 정확하게 파악하고 문제를 풀기 시작해야 한다.
    • 이전에는 시뮬레이션 문제를 맞닥뜨리면 무조건 풀기 시작했다.
      • 이럴 경우 결국 풀지 못하게 되는 경우도 많고 코드도 뒤죽박죽 되버린다….
    • 어떤 문제건, 문제의 조건과 상황을 완벽하게 이해하고 풀기 시작해야 안정적으로 푸는것이 가능하다.
    • 시뮬레이션 문제는 반드시
      • 문제를 정확하게 이해하고
      • 모든 조건을 정확하게 파악하고
      • case를 정확하게 분리해서 푸는것이 중요함
  • 문제
    • https://www.acmicpc.net/problem/14499
    • 크기가 NxM 맵에서 주사위 좌표가 순서대로 y,x 좌표로 주어질 때, 전체 맵에 바닥에 쓰이는 수 또한 입력된다.
    • k번의 이동횟수와 이에 대한 주사위 회전 방향이 입력된다.
    • k 번동안 주사위 맨 위의 숫자를 출력한다.
    • 조건
      • 주사위는 주어진 맵 안에서만 굴릴 수 있다.
      • 주사위가 처음 놓이는 위치의 숫자는 무조건 0이다.
      • 지도의 각 칸에는 정수가 하나씩 쓰여있다.
      • 주사위는 동(1), 서(2), 북(3), 남(4) 방향으로 움직인다.
      • 주사위를 굴렸을 때
        • 이동한 칸에 쓰여 있는 수가 0이면 주사위 바닥면의 숫자가 칸으로 복사된다.
          • 단, 주사위 숫자는 0이되는것이 아니라 유지된다!
          • 이것을 오해해서 시간을 꽤 날려먹음..
        • 이동한 칸에 숫자가 쓰여 있다면, 주사위 바닥면의 숫자가 칸의 숫자로 초기화되고 칸은 0이 된다.
  • 풀이
    • 문제를 나눠보면
      • 입력을 받아 맵과 명령어들을 저장한다.
      • 전체 명령어동안
      • 주사위를 굴린다.
        • 주사위는 맵 안으로만 구를 수 있다.
        • 맵 밖으로 넘어가면 그냥 넘어간다.
      • 주사위가 굴러간 위치의 맵의 값에 따라 주사위와 값을 초기화한다.
        • 맵에 값이 있다면 주사위 값을 초기화하고 맵을 비우고
        • 맵에 값이 없다면 맵 값만 초기화한다.
      • 현재 위치를 굴러간 위치로 초기화한다.
    • 주사위는 십자가 모양으로 나열한 후, 순서대로 0부터 5까지 매핑한다.
      • 이렇게 되면 주사위의 위쪽은 항상 인덱스 2가 된다.
        • 값을 출력할땐 주사위의 2번 인덱스 값만 출력하면 됨
      • 아래쪽은 항상 인덱스 5가 된다.
        • 값을 초기화 할 댄 5번 인덱스 값만 초기화 하면 됨
#pragma warning(disable:4996)
#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

int map[21][21]; // 주사위 맵
vector<int> order; // 명령어 저장용

int dx[] = { 0,1,-1,0,0 }; // 주사위 굴리기 방향
int dy[] = { 0,0,0,-1,1 };

int dice[] = { 0,0,0,0,0,0 }; // 주사위 값

void rotate_dice(int dir)
{
	int t_dice[] = { 0,0,0,0,0,0 };
	if (dir == 1)
	{//오른쪽 회전
		t_dice[0] = dice[0];
		t_dice[1] = dice[5];
		t_dice[2] = dice[1];
		t_dice[3] = dice[2];
		t_dice[4] = dice[4];
		t_dice[5] = dice[3];
	}
	if (dir == 2)
	{//왼쪽 회전
		t_dice[0] = dice[0];
		t_dice[1] = dice[2];
		t_dice[2] = dice[3];
		t_dice[3] = dice[5];
		t_dice[4] = dice[4];
		t_dice[5] = dice[1];
	}
	if (dir == 3)
	{//위 회전
		t_dice[0] = dice[2];
		t_dice[1] = dice[1];
		t_dice[2] = dice[4];
		t_dice[3] = dice[3];
		t_dice[4] = dice[5];
		t_dice[5] = dice[0];
	}
	if (dir == 4)
	{//아래 회전
		t_dice[0] = dice[5];
		t_dice[1] = dice[1];
		t_dice[2] = dice[0];
		t_dice[3] = dice[3];
		t_dice[4] = dice[2];
		t_dice[5] = dice[4];
	}
	for (int i = 0; i < 6; i++)
	{ // 계산된 주사위를 원래 주사위로 초기화
		dice[i] = t_dice[i];
	}
}

int main()
{
	int H, W, x, y, k;
	scanf("%d %d %d %d %d", &H, &W, &y, &x, &k);
	
	for (int j = 0; j < H; j++)
	{
		for (int i = 0; i < W; i++)
		{
			scanf("%d", &map[j][i]);
		}
	}

	for (int i = 0; i < k; i++)
	{
		int t;
		scanf("%d", &t);
		order.push_back(t);
	}

	int cx = x; // 현재 위치를 받고
	int cy = y;
	for (int i = 0; i < k; i++)
	{//전체 명령어 동안
		int nx = cx + dx[order[i]]; // 다음 위치를 만든다음
		int ny = cy + dy[order[i]];

		//만약 범위 벗어나지 않는다면
		if (0 <= nx && nx < W && 0 <= ny && ny < H)
		{
			//주사위 회전시키고
			rotate_dice(order[i]);

			//주사위 값 초기화와 맵 값 채우기
			if (map[ny][nx] != 0)
			{//만약 map에 값이 있다면
				dice[5] = map[ny][nx]; // 주사위 값 초기화
				map[ny][nx] = 0; // 맵을 비운다.
			}
			else
			{//만약 map에 값이 없다면(0)
				map[ny][nx] = dice[5]; // 맵 값을 초기화
			}
			printf("%d\n", dice[2]); // 주사위 위쪽 출력
			cx = nx; // 다음 위치 초기화
			cy = ny;
		}
	}
	//std::system("pause");
	return 0;
}