하루에 한 문제
[BOJ-14499] 주사위 굴리기 -Java 본문
https://www.acmicpc.net/problem/14499
package 시뮬레이션_review;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class boj_14499_주사위굴리기 {
static int N,M,x,y,K,map[][],move[],dice[];
static int dx[]= {0,0,0,-1,1};
static int dy[]= {0,1,-1,0,0};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
StringBuilder sb= new StringBuilder();
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];
move=new int[K];
dice=new int[6];
//맵
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++) {
move[i]=Integer.parseInt(st.nextToken());
}
solve(sb);
System.out.println(sb.toString());
}
private static void solve(StringBuilder sb) {
for(int i=0; i<K; i++) { //주사위의 이동만큼
int dir=move[i];
//x,y좌표 이동
int nx=x+dx[dir];
int ny=y+dy[dir];
if(nx<0 || ny<0 || nx>=N || ny>=M) continue; //범위넘어가면 skip
x=nx; //범위 안넘어가니까 x,y바꿔주기
y=ny;
if(dir==1 || dir==2) { //1번 2번은 위 좌 아래 우 앞 뒤
int []copyDice= {dice[0],dice[3],dice[5],dice[2],dice[4],dice[1]};
rollTheDice(copyDice,dir);
rearrange(copyDice,dir);
}
else { //3번 4번은 앞 위 뒤 아래 좌 우
int []copyDice= {dice[4],dice[0],dice[1],dice[5],dice[3],dice[2]};
rollTheDice(copyDice,dir);
rearrange(copyDice,dir);
}
if(map[x][y]==0) { //이동한 칸이 0 이면 -> 주사위 바닥면에 쓰인수가 칸에 복사
map[x][y]=dice[5];
}
else { //이동한칸이 0이 아니면 칸의 수가 주사위로 들어가고 칸은 0
dice[5]=map[x][y];
map[x][y]=0;
}
sb.append(dice[0]+"\n");
}
}
private static void rearrange(int[] copyDice, int dir) {
// 원래 주사위 ->>> 위 뒤 오 왼 앞 아래
if(dir==1 || dir==2) { //1번 2번은 위 좌 아래 우 앞 뒤
dice[0]=copyDice[0];
dice[1]=copyDice[5];
dice[2]=copyDice[3];
dice[3]=copyDice[1];
dice[4]=copyDice[4];
dice[5]=copyDice[2];
}
else {//3번 4번은 앞 위 뒤 아래 좌 우
dice[0]=copyDice[1];
dice[1]=copyDice[2];
dice[2]=copyDice[5];
dice[3]=copyDice[4];
dice[4]=copyDice[0];
dice[5]=copyDice[3];
}
}
private static void rollTheDice(int[] copyDice, int dir) {
if(dir==1||dir==3) { //1번, 3번은 오른쪽으로
int num=copyDice[3];
for(int i=3; i>0; i--) copyDice[i]=copyDice[i-1];
copyDice[0]=num;
}
else { //2번 ,4번은 왼쪽으로
int num=copyDice[0];
for(int i=0; i<3; i++) copyDice[i]=copyDice[i+1];
copyDice[3]=num;
}
}
}
소요시간 : 55분
처음에 어떻게 풀지 생각하고 규칙 찾는데 A4용지 한 장을 빼곡하게 사용했습니다.
일단 푼 방법을 설명해보자면
1 2 3 4 5 6
위 뒤 우 좌 앞 밑 -> 문제처럼 dice배열을 만들어 줍니다.
그리고 1번과 2번으로 주사위를 굴리게 되면 앞,뒤는 고정이고, 위, 좌, 밑, 우 만 바뀌게 됩니다.
마찬가지로 3번과 4번은 좌,우는 고정이고 앞, 위, 뒤, 밑 만 바뀌게 됩니다.
그리고 1번과 3번은 고정인 것을 빼고 나머지를 오른쪽으로 한 칸씩 밀어주면 됩니다.
또 2번과 4번은 고정인것을 빼고 나머지를 왼쪽으로 한 칸씩 밀어주면 됩니다.
직접 그려보시면 무슨 소린지 쉽게 이해하실 수 있습니다.
그래서 원래 dice배열을 1,2번이냐 vs 3,4번이냐에 따라
1,2번 위 좌 밑 오 앞 뒤 (고정)
3,4번 앞 위 뒤 밑 좌 우 (고정)
처럼 copyDice를 만들게 됩니다.
copyDice를 만드는 이유는 위에처럼 주사위를 바꾸게 되면 그림처럼 고정 2개를 빼고 나머지를 왼쪽이나, 오른쪽으로 밀어주면 주사위를 굴린 효과를 얻을 수 있기 때문입니다.
위의 내용처럼 주사위를 굴린 효과를 얻은 후 다시 Dice배열에 원래대로 넣어줍니다!
위를 토대로 큰 로직을 보게 되면
1. x,y좌표를 확인하고 갈 수 있다면 주사위를 굴린다. (rollTheDice 함수 이용)
2. copyDice를 원래의 주사위로 돌려준다 (rearrange 함수 이용)
3. 현재 주사위가 위치한 칸의 숫자를 확인한다.
3-1 만약 주사위가 위치한 칸이 0이라면 주사위 바닥면의 수를 칸에 복사한다.
3-2 만약 주사위가 위치한 칸이 0이 아니라면 칸의 수가 주사위의 바닥면으로 들어가고 칸은 0으로 바꿔준다.
4. 주사위 윗부분의 숫자 출력
그림으로 그려가면서 할 때는 쉬웠는데 뭔가 설명하려고 하니까 조금 어렵네요...
직접 그려보면서 하신다면 금방 이해하실 거라고 생각합니다!
'알고리즘 > 백준' 카테고리의 다른 글
[BOJ-14501] 퇴사 -Java (3) | 2021.01.29 |
---|---|
[BOJ-13458] 시험 감독 -Java (0) | 2021.01.29 |
[BOJ-2573] 빙산 -Java (0) | 2021.01.24 |
[BOJ-3190] 뱀 -Java (1) | 2021.01.08 |
[BOJ-16637] 괄호추가하기 -Java (1) | 2020.12.30 |