https://www.acmicpc.net/problem/14499
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
public class Main_14499 {
static int[] nextBase = {0, 3, 4, 2, 5}; //시작 위치 윗면 1, 동쪽 3 기준
static int[][] map;
static int[][] roll = {{0, 0},{0, 1}, {0, -1}, {-1, 0}, {1, 0}}; //동서북남
static Map<Integer, Integer> diceNum = new HashMap<>();
static int now = 6; //주사위 시작 바닥 = 6
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
//지도 크기
int N = Integer.parseInt(st.nextToken()); int M = Integer.parseInt(st.nextToken());
// 시작 좌표
int x = Integer.parseInt(st.nextToken()); int y = Integer.parseInt(st.nextToken());
// 명령 개수
int K = Integer.parseInt(st.nextToken());
map = new int[N][M];
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());
StringBuilder sb = new StringBuilder();
now = 6;
while (K-- > 0) {
int dir = Integer.parseInt(st.nextToken());
int nx = x + roll[dir][0];
int ny = y + roll[dir][1];
if(nx < 0 || nx >= N || ny < 0 || ny >= M)
continue;
sb.append(rollDice(nx, ny, dir)).append("\n");
x = nx; y = ny;
}
System.out.print(sb);
}
private static int rollDice(int x, int y, int dir) {
//next 값 정의
int next = nextBase[dir];
int upper = 7 - next;
//주사위를 dir 방향으로 굴리기
if (dir <= 2) {
nextBase[3 - dir] = now;
nextBase[dir] = 7 - now;
} else {
nextBase[7 - dir] = now;
nextBase[dir] = 7 - now;
}
//주사위 돌림 -> 다음 밑면 기준 값 갱신 후 윗면 출력
if (map[x][y] == 0 && diceNum.containsKey(next)) { //이동한 칸이 0인 경우 -> 바닥면의 수 복사됨
map[x][y] = diceNum.get(next);
} else {//이동한 칸이 0이 아닌 경우 -> 바닥면에 복사된 뒤 0으로
diceNum.put(next, map[x][y]);
map[x][y] = 0; //갱신 후 map은 0으로 변경
}
now = next;
return diceNum.getOrDefault(upper, 0);
}
}
💡 구현, 시뮬레이션
문제 조건
- 처음 주사위에는 모든 면에 0이 적혀 있음
- 지도의 각 칸에는 정수가 하나씩 쓰여져 있음
- 주사위를 굴렸을 때
- 이동한 칸의 숫자가 0인 경우) 주사위 바닥면에 쓰여있는 수가 칸에 복사됨
- 이동한 칸의 숫자가 0이 아닌 경우) 해당 숫자가 주사위의 바닥면으로 복사 + 지도의 숫자는 0이 됨
- 주사위 놓은 곳의 좌표, 이동시키는 명령이 주어진 경우 -> 주사위가 이동했을 때마다 상단에 쓰여있는 값을 구하라
- 주사위를 바깥으로 이동시키는 명령은 무시하며 출력도 금지
입력
1. 지도의 세로크기 N, 가로크기 M, 주사위 놓은 곳 지표 x, y, 명령의 개수 K
2 ~ 2 + N. 지도에 쓰여진 수가 차례로 주어짐. 주사위를 놓은 칸에 쓰여진 수는 항상 0
- 지도 각 칸에 쓰여있는 숫자 10 미만의 음이 아닌 정수
2 + N. 이동하는 명령이 순서대로 K 개 주어짐. 동 1, 서 2, 북 3, 남 4
출력
이동 시 마다 주사위 윗 면에 쓰인 수를 출력함. 바깥으로 이동시키려고 하는 경우에는 해당 명령 무시 및 출력 금지
풀이
- nextFloor라는 배열을 생성한 뒤, idx(주사위 굴리는 방향)별 그 다음 바닥에 오는 주사위 번호를 기록함
- 주사위를 굴리는 과정에 따라 아랫면에 같은 번호가 오더라도 nextFloor 구성이 달라질 수 있음
=> 해당 경우의 아랫면 번호를 기준으로 그때그때 갱신해나가야 함 - 동서로 이동하는 경우 >>> 북, 남 번호는 동일하고 굴리는 방향 (1 or 2)에 따라 nextFloor[1], [2] 값을 변경
- 북남으로 이동하는 경우 >>> 동, 서 번호는 동일하고, 굴리는 방향(3 or 4)에 따라 nextFloor[3], [4]값을 변경
- 주사위를 굴리는 과정에 따라 아랫면에 같은 번호가 오더라도 nextFloor 구성이 달라질 수 있음
- map에서 사용할 좌표변수는 x, y로 별개로 생성한 다음, 이동 번호에 따라 상하좌우로 +-1 해주며 값을 가져온다
- map[x][y]의 값이 0인지 아닌지에 따라 처리 방법 달라지는 것 주의
- 각 면마다 저장된 숫자를 갱신하기 위해 면 번호 별 값을 Map형태로 저장한 뒤 갱신해줌 (diceNum)
- 아랫면 번호를 저장할 변수 now(현재) next(다음 차례), 윗면을 저장할 변수 upper 지정 (이때, upper = 7 - now)
- 이때 출력해야 하는 수는 diceNum.get(upper), 없을 경우 0 출력
- now를 사용해 next 값을 구하고, 그 이후 nextFloor 값을 now를 사용해 갱신해준다.
'Algorithm > Beakjoon' 카테고리의 다른 글
[JAVA] 백준 3649번 : 로봇 프로젝트 (0) | 2024.05.12 |
---|---|
[JAVA] 백준 20436번 : ZOAC 3 (1) | 2024.05.03 |
[JAVA] 백준 12100번 : 2048(Easy) (0) | 2024.04.30 |
[JAVA] 백준 11404번 : 플로이드 (1) | 2024.04.25 |
[JAVA] 백준 12015번 : 가장 긴 증가하는 부분 수열 2 (0) | 2024.04.23 |