[BOJ 23288] 주사위 굴리기2
업데이트:
문제
- BOJ 23288
- 문제의 저작권은 Baekjoon Online Judge에 있습니다.
접근방식
문제에 제시된 순서대로 구현하면 쉽게 풀리는 문제이다.
1.좌표를 하나 이동할 때 다음에 갈 곳이 없으면 이동방향을 반대로 바꾼다.
2.좌표 이동 후 주사위도 굴려줘야 하므로 현재 방향에 따라 주사위 위치를 바꿔준다. 주사위 면적값은 위의 인덱스를 1,아래6,왼4,오3,앞5,뒤2로 고정시키고 각 면적에 오는 번호를 배열로 관리하였다.
3.현재 map[nowX][nowY]
에서 동서남북으로 갈 수 있으면서 점수가 현재 위치와 같은 하나의 그룹을 BFS
로 찾아준다. 그러기 위해 큐를 사용하였고, 좌표를 찾을때 마다 cnt
를 하나씩 증가시켰다.
4.주사위에 아랫면에 온 번호와 현재 위치의 점수를 비교해서 방향을 바꿔준다. 나는 일일히 조건문을 써서 바꿔주었다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int N, M, K; // 행,열,이동횟수
static int[][] map; // 전체맵, 누적합 저장
static boolean[][] visited; // 방문했는지 체크
static int[] diceArr = { 0, 1, 2, 3, 4, 5, 6 }; // 주사위 면적값, 위1 아래6 왼4 오3 앞5 뒤2
static int nowX = 1, nowY = 1; // 현재 좌표
static int nowDir = 0;
static int[][] dArr = { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; // 동서남북
static Queue<Point> q;
static int Ans; //점수 합
static class Point{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) throws IOException {
st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
M = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
map = new int[N + 1][M + 1]; // 1,1부터 시작
for (int i = 1; i <= N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 1; j <= M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
} // End input
for (int k = 0; k < K; k++) {
// 1. 주사위가 이동 방향으로 한 칸 굴러간다.
// 만약, 이동 방향에 칸이 없다면, 이동 방향을 반대로 한 다음 한 칸 굴러간다.
while(true) {
int nx = nowX + dArr[nowDir][0];
int ny = nowY + dArr[nowDir][1];
if(nx>=1 && nx<=N && ny>=1 && ny<=M) {
nowX = nx;
nowY = ny;
break;
}
//이동방향에 칸이 없으면 방향 반대로
if(nowDir == 0) nowDir = 1;
else if(nowDir == 1) nowDir = 0;
else if(nowDir == 2) nowDir = 3;
else nowDir = 2;
}
switchDice(); //주사위도 굴리기
// 2. 주사위가 도착한 칸 (x, y)에 대한 점수를 획득한다.
Ans += getScore();
// 3. 주사위의 아랫면에 있는 정수 A와 주사위가 있는 칸 (x, y)에 있는 정수 B를 비교해 이동 방향을 결정
if(diceArr[6] > map[nowX][nowY]) { //시계방향 회전
if(nowDir == 0) nowDir = 2;
else if(nowDir == 1) nowDir = 3;
else if(nowDir == 2) nowDir = 1;
else nowDir = 0;
}else if(diceArr[6] < map[nowX][nowY]) { //반시계방향 회전
if(nowDir == 0) nowDir = 3;
else if(nowDir == 1) nowDir = 2;
else if(nowDir == 2) nowDir = 0;
else nowDir = 1;
}
}
System.out.println(Ans);
}
private static int getScore() {
//현재 위치에서 동서남북 갈수 있으면서 같은 점수인칸의 개수 구하기
int nowScore = map[nowX][nowY]; //현재칸의 점수
q = new LinkedList<>();
visited = new boolean[N + 1][M + 1];
int cnt = 1; //이동가능 칸수
q.add(new Point(nowX, nowY));
visited[nowX][nowY] = true;
while(!q.isEmpty()) {
int size = q.size();
for(int s=0; s<size; s++) {
Point p = q.poll();
for(int d=0; d<4; d++) {
int nx = p.x + dArr[d][0];
int ny = p.y + dArr[d][1];
if(nx>=1 && nx<=N && ny>=1 && ny<=M && !visited[nx][ny] &&
map[nx][ny] == nowScore ) {
visited[nx][ny] = true;
cnt++;
q.add(new Point(nx, ny));
}
}
}
}
return cnt * nowScore;
}
private static void switchDice() {
int tmp = diceArr[1];
switch (nowDir) {
case 0: // 동쪽
diceArr[1] = diceArr[4];
diceArr[4] = diceArr[6];
diceArr[6] = diceArr[3];
diceArr[3] = tmp;
break;
case 1: // 서쪽
diceArr[1] = diceArr[3];
diceArr[3] = diceArr[6];
diceArr[6] = diceArr[4];
diceArr[4] = tmp;
break;
case 2: // 남쪽
diceArr[1] = diceArr[2];
diceArr[2] = diceArr[6];
diceArr[6] = diceArr[5];
diceArr[5] = tmp;
break;
case 3: // 북쪽
diceArr[1] = diceArr[5];
diceArr[5] = diceArr[6];
diceArr[6] = diceArr[2];
diceArr[2] = tmp;
break;
}
}
}