Algorithm Problem Solving/BOJ

백준 23288 주사위 굴리기 2 (C++)

dashwood 2022. 6. 8. 20:28

문제 링크

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

 

23288번: 주사위 굴리기 2

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

www.acmicpc.net

 

문제 풀이

주사위의 이동은 주사위 굴리기 1 처럼 구현했다. 그럼에도 불구하고 주사위 굴리는 부분 구현 실수한 것을 계속 발견하지 못했던 문제이다. 그것도 모르고 엉뚱한 곳에서 삽질했던 문제.. 아니 주사위 굴리기 1은 잘 풀어놓고 왜...?

 

 

#include <iostream>
#include <vector>
#include <queue>
#include <tuple>
using namespace std;

int dice[7] = { 0, 1, 2, 3, 4, 5, 6 };
int dice2[7] = { 0, 1, 2, 3, 4, 5, 6 };
int dx[] = { 0, -1, 0, 1 };
int dy[] = { 1, 0, -1, 0 }; //반시계 방향 순

int bfs(vector<vector<int>>& a, int x, int y, int num) {
    //x, y에서 연속해서 이동할 수 있는 칸의 수, num과 같은 곳으로 이동
    int n = a.size();
    int m = a[0].size();

    vector<vector<bool>> d(n, vector<bool>(m, false));
    queue<pair<int, int>> q;
    q.push(make_pair(x, y));
    d[x][y] = true;

    while (!q.empty()) {
        int x, y;
        tie(x, y) = q.front();
        q.pop();

        for (int k = 0; k < 4; k++) {
            int nx = x + dx[k];
            int ny = y + dy[k];

            if (0 <= nx && nx < n && 0 <= ny && ny < m) {
                if (a[nx][ny] == num && d[nx][ny] == false) {
                    d[nx][ny] = true;
                    q.push(make_pair(nx, ny));
                }
            }
        }
    }

    int cnt = 0;

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (d[i][j]) {
                cnt += 1;
            }
        }
    }
   
    return cnt; //x, y칸에서 연속해서 이동할 수 있는 칸의 수 C
}

int main() {
    int n, m, k;
    cin >> n >> m >> k;
    vector<vector<int>> a(n, vector<int>(m));
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> a[i][j];
        }
    }

    int x = 0;
    int y = 0; //주사위의 아랫면이 있는 지도에서의 위치
    int dir = 0; //주사위의 시작 방향

    int ans = 0; //각 이동에서 획득하는 점수의 합
    while (k--) { //주사위가 k번 이동
        //주사위가 이동 방향으로 한 칸 굴러감
        int nx = x + dx[dir];
        int ny = y + dy[dir];
       
        if (nx < 0 || nx >= n || ny < 0 || ny >= m) { //이동방향에 칸이 없다면 이동방향 반대로 한 다음 한 칸 이동
            dir = (dir + 2) % 4;
            nx = x + dx[dir];
            ny = y + dy[dir];

        }

        // 도착한 칸(x, y)에 대한 점수 획득
        int cnt = bfs(a, nx, ny, a[nx][ny]); //현재 칸에 있는 정수와 연속해서 갈 수 있는 칸의 개수
        ans += (cnt * a[nx][ny]);

        //주사위의 밑면
        if (dir == 0) { //동쪽
            int temp = dice[6];
            dice[6] = dice[3];
            dice[3] = dice[1];
            dice[1] = dice[4];
            dice[4] = temp;
        }
        else if (dir == 1) { //북쪽
            int temp = dice[1];
            dice[1] = dice[5];
            dice[5] = dice[6];
            dice[6] = dice[2];
            dice[2] = temp;
        }
        else if (dir == 2) { //서쪽
            int temp = dice[4];
            dice[4] = dice[1];
            dice[1] = dice[3];
            dice[3] = dice[6];
            dice[6] = temp;
        }
        else if (dir == 3) { //남쪽
            int temp = dice[2];
            dice[2] = dice[6];
            dice[6] = dice[5];
            dice[5] = dice[1];
            dice[1] = temp;
        }

        // 주사위의 이동방향 결정
        if (dice[6] > a[nx][ny]) { //주사위의 아랫면에 있는 정수 A > 칸에 있는 정수 B -> 90도 시계방향
            dir = (dir + 3) % 4;
        }
        else if (dice[6] < a[nx][ny]) { // -> 90도 반시계 방향
            dir = (dir + 1) % 4;
        }
        x = nx;
        y = ny;
 
    }

    cout << ans << '\n';

    return 0;
}