알고리즘/알고리즘문풀

BOJ - 주사위 굴리기2 23288번 (JAVA)

developer-ellen 2022. 3. 4. 00:56

❓ 문제 - 백준 주사위 굴리기2 23288번 - JAVA 풀이법

 

출처 

(https://www.acmicpc.net/problem/23288)

 

23288번: 주사위 굴리기 2

크기가 N×M인 지도가 존재한다. 지도의 오른쪽은 동쪽, 위쪽은 북쪽이다. 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다. 가장 왼

www.acmicpc.net

 

 

📝 문제해결법

1. 이 문제는 시뮬레이션 + BFS 으로 문제를 풀었다.

  • K번의 주사위를 굴릴 때 현재 방향으로 이동한 뒤 점수 계산을 위해 그 이동한 곳에 위치에 있는 점수와 같은 점수가 몇 개 인접했는지 카운트 하는 것을 BFS로 구현하였다. 
  • 전체 구현 흐름은 다음과 같다. 주사위의 방향으로 이동해보고 만약 범위를 벗어나는 곳으로 이동하지 못한다면 이동방향을 바꿔서 그곳으로 이동하게 구현한다.
  • 또한 dice라는 배열을 만들어서 주사위의 윗면-뒷면-오옆-왼옆-앞면-바닥면을 각 인덱스에 맞춰서 주사위 숫자를 넣어준다.
  • 그리고 change_dice()라는 함수를 통해 주사위를 굴려진 방향에 맞춰서 각 면에 바껴진 주사위 숫자를 갱신한다.
  • BFS로 해당 위치에 적힌 점수와 같은 점수가 몇 개 인접했는지 카운트 해줘서 카운트 갯수 * 적힌 점수 해서 점수를 증가시켜준다.
  • 그리고 주사위의 바닥면과 map에 적힌 숫자와 비교해서 문제에 주어진 조건대로 주사위의 이동방향을 바꾼다.
  • 만약 주사위 바닥면의 숫자가 map에 적힌 숫자보다 크다면 시계방향으로 변경 처리, 그리고 주사위 바닥면의 숫자가 map에 적힌 숫자보다 작다면 반시계방향 변경 처리, 그리고 두 숫자가 같다면 방향 처리를 하지 않는다.

2. 주사위 굴러가는 방향에 맞춰 주사위 면의 값 변경 => change_dice()

  • dice 인덱스에 맞는 각 주사위 면은 윗면(0)-뒷면(1)-오옆(2)-왼옆(3)-앞면(4)-바닥면(5)
  • 만약 동쪽으로 주사위가 굴러가면 윗면->오옆->아랫면->왼옆->윗면 으로 주사위의 값이 변경된다.
  • 만약 남쪽으로 주사위가 굴러가면 윗면->앞면->바닥면->뒷면->앞면 으로 주사위의 값이 변경된다.
  • 만약 서쪽으로 주사위가 굴러가면 윗면->왼옆->바닥면->오옆->윗면 으로 주사위의 값이 변경된다.
  • 만약 북쪽으로 주사위가 굴러가면 윗면->뒷면->바닥면->앞면->윗면 으로 주사위의 값이 변경된다.
  public static void change_dice(){
  		// 동쪽
        if(dir == 0){
            int temp = dice[0];
            dice[0] = dice[3];
            dice[3] = dice[5];
            dice[5] = dice[2];
            dice[2] = temp;

        } else if(dir == 1){  // 남쪽
            int temp = dice[0];
            dice[0] = dice[1];
            dice[1] = dice[5];
            dice[5] = dice[4];
            dice[4] = temp;
        } else if(dir == 2){ // 서쪽
            int temp = dice[0];
            dice[0] = dice[2];
            dice[2] = dice[5];
            dice[5] = dice[3];
            dice[3] = temp;
        } else if(dir == 3){ // 북쪽
            int temp = dice[0];
            dice[0] = dice[4];
            dice[4] = dice[5];
            dice[5] = dice[1];
            dice[1] = temp;
        }
    }

 

3. 느낀점

  • 기존 삼성기출의 주사위굴리기1을 풀어보면 거기에 bfs만 추가하여 구현하면 될 것이라고 느꼈다...
  • 시뮬레이션의 핵심은 주어진 조건에 맞춰 잘 구현하면 되는 것이다...
  • 주사위가 굴러갔을 때 굴러간 방향에 맞춰 주사위 면들의 값들이 변경되는 부분을 신경 잘 써서 구현해야 한다!!

 

💻 소스코드

// BOJ - 주사위굴리기2(23288번)
// 구현 + BFS

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main_23288 {
    // 윗면 - 뒷면 - 오옆 - 왼옆 - 앞면 - 바닥면
    public static int[] dice = {1, 2, 3, 4, 5, 6};

    // 동 - 남 - 서 - 북
    public static int[] dx = {0, 1, 0, -1};
    public static int[] dy = {1, 0, -1, 0};
    public static int[][] map;
    public static int N, M, K, dir;
    public static int d_x, d_y;
    public static class Node {
        int x;
        int y;
        public Node(int x, int y){
            this.x = x;
            this.y = y;
        }
    }
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer 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];

        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());
            }
        }

        dir = 0;
        int score = 0;
        int rotate_cnt = 1;
        d_x = 1;
        d_y = 1;
        while (rotate_cnt++ <= K){
            // 해당 방향으로 이동
            d_x += dx[dir];
            d_y += dy[dir];
            // 이동할 수 없는 곳 ?
            if(d_x < 1 || d_x > N || d_y < 1 || d_y > M){
                d_x -= dx[dir];
                d_y -= dy[dir];
                // 이동방향 반대로 전환
                dir = (dir+2) % 4;
                d_x += dx[dir];
                d_y += dy[dir];
            }

            // 주사위 면 변화
            change_dice();
            int cnt = bfs();
            // 점수 획득
            score += (cnt*map[d_x][d_y]);

            // 이동방향 변경
            if(dice[5] > map[d_x][d_y]){
                dir = (dir + 1) % 4;
            } else if(dice[5] < map[d_x][d_y]){
                dir = (dir==0?3:dir-1);
            }
        }

        sb.append(score);
        System.out.println(sb.toString());
    }

    public static void change_dice(){
        if(dir == 0){
            int temp = dice[0];
            dice[0] = dice[3];
            dice[3] = dice[5];
            dice[5] = dice[2];
            dice[2] = temp;

        } else if(dir == 1){
            int temp = dice[0];
            dice[0] = dice[1];
            dice[1] = dice[5];
            dice[5] = dice[4];
            dice[4] = temp;
        } else if(dir == 2){
            int temp = dice[0];
            dice[0] = dice[2];
            dice[2] = dice[5];
            dice[5] = dice[3];
            dice[3] = temp;
        } else if(dir == 3){
            int temp = dice[0];
            dice[0] = dice[4];
            dice[4] = dice[5];
            dice[5] = dice[1];
            dice[1] = temp;
        }
    }

    public static int bfs(){
        boolean[][] visited = new boolean[N+1][M+1];
        int cnt = 1;
        Queue<Node> q = new LinkedList<>();
        q.offer(new Node(d_x, d_y));
        visited[d_x][d_y] = true;
        while (!q.isEmpty()){
            Node node = q.poll();
            for(int d=0;d<4;d++){
                int nx = node.x + dx[d];
                int ny = node.y + dy[d];

                if(1 <= nx && nx <= N && 1 <= ny && ny <= M){
                    if(!visited[nx][ny] && map[nx][ny] == map[d_x][d_y]){
                        visited[nx][ny] = true;
                        cnt++;
                        q.offer(new Node(nx, ny));
                    }
                }
            }
        }
        return cnt;
    }


}