삼성 SW 역량테스트 백준 주사위 굴리기 14499

1. 삼성 SW 역량테스트 백준 주사위 굴리기 14499문제

1.1. 아이디어

  1. N*M의 상하좌우의 지도가 주어진다.
  2. 주사위 전개도를 살펴보면 다음과 같다.
    2(top)
    4(left) 1(up) 3(right)
    5(bottom)
    6(down)

해당 문제에서는 다음과 같은 변수명으로 주사위 문제를 풀어볼 예정이다.

  1. 주사위의 문제 조건을 살펴보면 다음과 같다.
    (1) 가장 처음 주사위 모든면에 ‘0’의 값으로 초기화가 된 상태로 진행한다.
    (2) 지도 각 칸에 N*M 가로, 세로 형태의 값을 입력받는다.
    (3) 좌표는 X,Y값으로 구분한다.
    (4) 지도가 ‘0’일 경우
  • 주사위 바닥을 지도칸에 복사시킨다.
    (5) 지도가 ‘0’이 아닐 경우
  • 지도칸 숫자를 주사위바닥에 복사한다.
  • 지도칸에 쓰여진 수를 ‘0’으로 초기화 한다.
    (6) 지도의 N*M범위를 벗어날 수 없다. 즉, 이동하면 안되고 명령을 무시해야한다.
    (7) 명령은 동 1 서 2 북 3 남 4의 형태로 값의 입력이 주어진다.
    (8) 입력은 세로N, 가로M, 주사위 놓은곳의 좌표 X Y 명령어의 개수 K가 주어진다.
    (9) 명령어의 개수만큼 명령어들을 입력받는다.

1.2. 컴퓨팅적 사고

  1. 가로n ,세로 m, 주사위 좌표 x/y, 명령어의 개수 k를 입력받는다.
  2. command로 주어진 1,2,3,4 방향에 대한 리스트를 담는 List를 선언하여 저장한다.
  3. 현재 주사위의 상태를 가지고 있는 주사위 클래스 Dice클래스를 선언한다.
  4. 현재 주사위의 상태를 가지고 있는 x,y 초기에 주어지는 주사위의 비용은 0이므로 모든값들을 생성자로 초기화를 진행한다.
  5. 명령어의 순서대로 주사위를 굴린다.
  • 다음 이동 위치 = 현재 위치 + 명령어 이동 방향에 따른 값 X,Y
  1. 주사위의 상태를 복사하여 주사위를 굴릴때 값을 변경시킨다.
  • 값을 담고있는 하나의 변수를 선언하여 주사위에 쓰여진 비용값들을 담아 놓는다.
  1. 현재 이동된 값이 지도 범위에 만족하는지 확인한다.
  • 지도의 범위를 만족하면 False, 만족하지못하면 True를 리턴한다. True를 리턴할 경우 문제의 조건에 나와있듯이 값을 출력하지 않고 다음의 경우로 이동한다. 따라서 continue를 통해 해당 경우를 뛰어넘는다.
  1. 지도의 값이 ‘0’ 일 경우
  • 주사위바닥수가 칸에 복사된다.
  1. 지도의 값이 ‘0’이 아닐경우 칸에 쓰여진 수가 주사위 바닥면으로 복사한다. 그리고 칸에 쓰여진 수를 0으로 변경한다.

주사위 회전의 경우

사용할 변수

지금 부터 말하는 값들의 기준은 내가 앞에서 바라봤을때의 기준으로 설명을 진행하겠다. top 기준 위 bottom 기준 아래 left 기준 왼쪽 right 기준 오른쪽 up 주사위 맨위 down 주사위 맨 바닥의 총 6가지의 주사위의 경우를 사용한다.

CASE1) 오른쪽으로 주사위를 굴릴 경우

  1. UP -> RIGHT
  2. RIGHT -> DOWN
  3. DOWN -> LEFT
  4. LEFT -> UP

CASE2) 왼쪽으로 주사위를 굴릴 경우

  1. UP -> LEFT
  2. LEFT -> DOWN
  3. DOWN -> RIGHT
  4. RIGHT -> UP

CASE3) 위로 주사위를 굴릴 경우

  1. UP -> TOP
  2. TOP -> DOWN
  3. DOWN -> BOTTOM
  4. BOTTOM -> UP

CASE4) 아래로 주사위를 굴릴 경우

  1. TOP -> UP
  2. UP -> BOTTOM
  3. BOTTOM -> DOWN
  4. DOWN -> TOP

총 4가지의 오른쪽, 왼쪽, 위로, 아래로 주사위를 굴리는 경우를 처리할 수 있습니다. 해당 사항에서는 문제에서 주어진대로 동서북남의 경우로 처리를 진행합니다.
그리고, 해당 경우의 수를 모두 지나고나서 맨위의 주사위에 있는 비용값을 출력해주고, Dice의 객체의 currX, currY의 값을 현재 이동된 값으로 갱신하여 값을 출력시켜주면 해당 문제를 해결 할 수 있습니다. 약 40분정도 소요되었던 문제였고, 대표적인 시뮬레이션 문제라고 생각합니다.

1.3. 소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package Samsung.done;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class 주사위굴리기_14499{
static int n,m,x,y,k;
static int[][] map;
static int[][] dir = {{0,1},{0,-1},{-1,0},{1,0}}; // 동서북
static List<Integer> commandList;
static int upCopy; // 1
static int topCopy; // 2
static int rightCopy; // 3
static int leftCopy; // 4
static int bottomCopy; // 5
static int downCopy; // 6

public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
x = Integer.parseInt(st.nextToken());
y = Integer.parseInt(st.nextToken());
k = Integer.parseInt(st.nextToken());
map = new int[n][m];
commandList = new ArrayList<>();
for(int i=0; i<n; i++){
st = new StringTokenizer(br.readLine());
for(int j=0; j<m; j++){
map[i][j] = Integer.parseInt(st.nextToken());
}
}
st = new StringTokenizer(br.readLine());
for(int i=0; i<k; i++){
commandList.add(Integer.parseInt(st.nextToken()));
}
// 현재 주사위 상태 객체
Dice dice = new Dice(x,y,0,0,0,0,0,0);

// 명령어 대로 주사위를 돌린다.
for (int i = 0; i < commandList.size(); i++) {
int dx = dice.currX;
int dy = dice.currY;
// 현재 주사위 방향
int currDir = commandList.get(i)-1;
int mx = dx + dir[currDir][0];
int my = dy + dir[currDir][1];

// 주사위 이동방향 체크하기
if(isCheckRange(mx,my)) continue;
diceStateSave(dice);
diceTumble(dice, currDir);

// 지도가 0일 경우
if(map[mx][my] == 0){
map[mx][my] = dice.down;
}
// 지도가 0이 아닐 경우
else {
dice.down = map[mx][my];
map[mx][my] = 0;
}
System.out.println(dice.up);
dice.currX = mx;
dice.currY = my;
}
}

private static void diceTumble(Dice dice, int currDir) {
if(currDir == 0){
dice.right = upCopy;
dice.down = rightCopy;
dice.left = downCopy;
dice.up = leftCopy;
}else if(currDir == 1){
dice.left = upCopy;
dice.down = leftCopy;
dice.right = downCopy;
dice.up = rightCopy;
}else if(currDir == 2){
dice.top = upCopy;
dice.down = topCopy;
dice.bottom = downCopy;
dice.up = bottomCopy;
}else if(currDir == 3){
dice.up = topCopy;
dice.bottom = upCopy;
dice.down = bottomCopy;
dice.top = downCopy;
}
}

private static void diceStateSave(Dice dice) {
upCopy = dice.up;
topCopy = dice.top;
rightCopy = dice.right;
leftCopy = dice.left;
bottomCopy = dice.bottom;
downCopy = dice.down;
}

private static boolean isCheckRange(int mx, int my) {
if(mx < 0 || mx >= n || my < 0 || my >= m) return true;
return false;
}
private static class Dice {
int currX;
int currY;

// 윗면, 아랫면
int up; // 1
int top; // 2
int right; // 3
int left; // 4
int bottom; // 5
int down; // 6

public Dice(int currX, int currY, int up, int top, int right, int left, int bottom, int down) {
this.currX = currX;
this.currY = currY;
this.up = up;
this.top = top;
this.right = right;
this.left = left;
this.bottom = bottom;
this.down = down;
}
}
}