백준 23288 주사위 굴리기 2(Java,자바)

jonghyukLee·2021년 11월 23일
0

이번에 풀어본 문제는
백준 23288번 주사위 굴리기2 입니다.

📕 문제 링크

❗️코드

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 Point
{
    int x,y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}
class Dice
{
    int x,y,dir;
    int top,bot,left,right,front,back;

    public Dice(int x, int y, int dir)
    {
        this.x = x;
        this.y = y;
        this.dir = dir;
    }

    public void setTop(int top) {
        this.top = top;
    }

    public void setBot(int bot) {
        this.bot = bot;
    }

    public void setLeft(int left) {
        this.left = left;
    }

    public void setRight(int right) {
        this.right = right;
    }

    public void setFront(int front) {
        this.front = front;
    }

    public void setBack(int back) {
        this.back = back;
    }
}
public class Main {
    static int N,M,K;
    static int answer;
    static Dice dice;
    static int [] points;
    static int [][] group;
    static int [][] map;
    static int [] dx = {-1,0,1,0};
    static int [] dy = {0,1,0,-1}; // 상 우 하 좌

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        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];
        group = new int[N+1][M+1];
        points = new int[401];

        dice = new Dice(1,1,1);
        dice.setTop(1);
        dice.setFront(2);
        dice.setRight(3);
        dice.setLeft(4);
        dice.setBack(5);
        dice.setBot(6);

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

        int group_num = 1;
        for(int i = 1; i <= N; ++i)
        {
            for(int j = 1; j <= M; ++j)
            {
                if(group[i][j] < 1)
                {
                    bfs(i,j,map[i][j],group_num++);
                }
            }
        }

        while(K-- > 0) move();
        System.out.print(answer);
    }
    static void move()
    {
        int mx = dice.x + dx[dice.dir];
        int my = dice.y + dy[dice.dir];

        if(!isValid(mx,my))
        {
            dice.dir = (dice.dir + 2) % 4;
            mx = dice.x + dx[dice.dir];
            my = dice.y + dy[dice.dir];
        }

        roll(dice.dir);
        dice.x = mx;
        dice.y = my;

        int cur_group = group[dice.x][dice.y];
        answer += points[cur_group];

        int bot = dice.bot;
        int tile = map[dice.x][dice.y];
        if(bot > tile) dice.dir = (dice.dir + 1) % 4;
        else if(bot < tile) dice.dir = (dice.dir + 3) % 4;

    }
    static void roll(int dir)
    {
        int tmp_top = dice.top;
        int tmp_bot = dice.bot;
        int tmp_left = dice.left;
        int tmp_right = dice.right;
        int tmp_front = dice.front;
        int tmp_back = dice.back;
        if(dir == 0)
        {
            dice.setTop(tmp_back);
            dice.setBot(tmp_front);
            dice.setFront(tmp_top);
            dice.setBack(tmp_bot);
        }
        else if(dir == 1)
        {
            dice.setTop(tmp_left);
            dice.setBot(tmp_right);
            dice.setLeft(tmp_bot);
            dice.setRight(tmp_top);
        }
        else if(dir == 2)
        {
            dice.setTop(tmp_front);
            dice.setBot(tmp_back);
            dice.setFront(tmp_bot);
            dice.setBack(tmp_top);
        }
        else
        {
            dice.setTop(tmp_right);
            dice.setBot(tmp_left);
            dice.setLeft(tmp_top);
            dice.setRight(tmp_bot);
        }
    }
    static void bfs(int i, int j,int val,int group_num)
    {
        Queue<Point> q = new LinkedList<>();
        q.add(new Point(i,j));
        int cnt = 0;
        while(!q.isEmpty())
        {
            Point cur = q.poll();
            if(group[cur.x][cur.y] > 0) continue;
            cnt++;
            group[cur.x][cur.y] = group_num;

            for(int idx = 0; idx < 4; ++idx)
            {
                int mx = cur.x + dx[idx];
                int my = cur.y + dy[idx];

                if(!isValid(mx,my) || group[mx][my] > 0 || val != map[mx][my]) continue;
                q.add(new Point(mx,my));
            }
        }
        points[group_num] = cnt * val;
    }
    static boolean isValid(int x, int y)
    {
        return x > 0 && y > 0 && x <= N && y <= M;
    }
}

📝 풀이

주사위를 K번 굴렸을 때 얻을 수 있는 점수를 출력하는 문제입니다.
주사위의 초기 세팅이 주어졌고, 동쪽 방향을 갖고 시작합니다. 주사위가 방향에 따라 이동하여 발판을 밟았을 때, 그 발판에 쓰여진 숫자와 같은 인접한 발판의 개수를 곱한 점수를 획득하며 주사위 바닥에 쓰여진 숫자와 발판 숫자를 비교하여 방향도 수정해줍니다. 범위를 벗어날 경우는 방향을 반대로 뒤집습니다.
먼저 각 발판의 번호를 map에 담아줍니다.
인접한 숫자를 그룹화하기 위해 group 배열을 같은 크기로 생성해주고, 만약 group배열의 값이 1보다 작을경우, 그룹화가 이루어지지 않았다고 판단하여 해당 인덱스부터 bfs탐색을 시작합니다.
cnt값을 누적하여 인접한 숫자의 개수를 세어주고, 모든 이동이 끝났을 때 group의 번호를 인덱스로 하는 points 배열에 cnt * val를 해주면 해당 그룹의 점수를 담아둘 수 있습니다.
주사위의 이동과 방향 회전은 간단하게 구현할 수 있으며, K번 반복 후에 누적된 answer값을 출력해주면 됩니다.

📜 후기

그룹화를 할때 dfs를 사용했더니, 제대로 꼬여버려서 꽤나 고생한 문제입니다..
ㅗ ㅓ ㅏ ㅜ 같은 모양을 탐색할때는 dfs가 적절하지 않다는걸 예전에 문제풀면서 깨달았었는데, 오랜만에 마주하니 깜빡했어요 ㅎㅎ..
반례를 찾지못해서 애먹고 있었는데, 오픈카톡방에 질문했더니 어떤 은혜로운분이 도와주셨어요.. 저도 얼른 강해져서 누군가에게 조언을 해주고싶군뇨

profile
머무르지 않기!

0개의 댓글