[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;
		}
	}
}