ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [백준] 12100 2048(easy)
    알고리즘/알고리즘 풀이 2020. 2. 12. 21:45

    문제 설명

    2048 게임은 4×4 크기의 보드에서 혼자 즐기는 재미있는 게임이다. 이 링크를 누르면 게임을 해볼 수 있다.

    이 게임에서 한 번의 이동은 보드 위에 있는 전체 블록을 상하좌우 네 방향 중 하나로 이동시키는 것이다. 이때, 같은 값을 갖는 두 블록이 충돌하면 두 블록은 하나로 합쳐지게 된다. 한 번의 이동에서 이미 합쳐진 블록은 또 다른 블록과 다시 합쳐질 수 없다. (실제 게임에서는 이동을 한 번 할 때마다 블록이 추가되지만, 이 문제에서 블록이 추가되는 경우는 없다)

     

    <그림 1>의 경우에서 위로 블록을 이동시키면 <그림 2>의 상태가 된다. 여기서, 왼쪽으로 블록을 이동시키면 <그림 3>의 상태가 된다.

     

    <그림 4>의 상태에서 블록을 오른쪽으로 이동시키면 <그림 5>가 되고, 여기서 다시 위로 블록을 이동시키면 <그림 6>이 된다. 여기서 오른쪽으로 블록을 이동시켜 <그림 7>을 만들 수 있다.<그림 10>에서 위로 블록을 이동시키면 <그림 11>의 상태가 된다. 

     

    <그림 12>의 경우에 위로 블록을 이동시키면 <그림 13>의 상태가 되는데, 그 이유는 한 번의 이동에서 이미 합쳐진 블록은 또 합쳐질 수 없기 때문이다.

     

     

    마지막으로, 똑같은 수가 세 개가 있는 경우에는 이동하려고 하는 쪽의 칸이 먼저 합쳐진다. 예를 들어, 위로 이동시키는 경우에는 위쪽에 있는 블록이 먼저 합쳐지게 된다. <그림 14>의 경우에 위로 이동하면 <그림 15>를 만든다.

    이 문제에서 다루는 2048 게임은 보드의 크기가 N×N 이다. 보드의 크기와 보드판의 블록 상태가 주어졌을 때, 최대 5번 이동해서 만들 수 있는 가장 큰 블록의 값을 구하는 프로그램을 작성하시오.

     

    입력

    • 첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.

    입력 예

    3
    2 2 2
    4 4 4
    8 8 8

    출력

    • 최대 5번 이동시켜서 얻을 수 있는 가장 큰 블록을 출력한다.

    출력 예

    16

     

    풀이

    #include <iostream>
    #include <queue>
    #include <algorithm>
    #define MAX_SIZE 20
    using namespace std;
    
    int N;
    int block[MAX_SIZE][MAX_SIZE];
    int ans;
    
    int Max(int x, int y) { return x < y ? y : x; }
    
    // copy from arr2 to arr1
    void copy(int(*arr1)[MAX_SIZE], int(*arr2)[MAX_SIZE]) {
        for (int i = 0; i < N; i++){
            for (int j = 0; j < N; j++){
                arr1[i][j] = arr2[i][j];
            }
        }
    }
    
    // move
    void move(int d) {
        queue<int> q;
        switch(d) {
            // 동
            case 0:
                for (int i = 0; i < N; i++) {
                    for (int j = N-1; j >= 0; j--) {
    
                        if (block[i][j] != 0) {
                            q.push(block[i][j]);
                            block[i][j] = 0;
                        }
                    }
    
                    int num = 0;
                    int idx = N-1;
    
                    while(!q.empty()) {
                        num = q.front();
                        q.pop();
    
                        if (block[i][idx] == 0) block[i][idx] = num;
                        else if (block[i][idx] == num) {
                            block[i][idx] *= 2;
                            idx--;
                        }
                        else {
                            block[i][--idx] = num;
                        }
                    }
                }
                break;
    
            // 서
            case 1:
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < N; j++) {
    
                        if (block[i][j] != 0) {
                            q.push(block[i][j]);
                            block[i][j] = 0;
                        }
                    }
    
                    int num = 0;
                    int idx = 0;
    
                    while(!q.empty()) {
                        num = q.front();
                        q.pop();
    
                        if (block[i][idx] == 0) block[i][idx] = num;
                        else if (block[i][idx] == num) {
                            block[i][idx] *= 2;
                            idx++;
                        }
                        else {
                            block[i][++idx] = num;
                        }
                    }
                }
                break;
    
            // 남
            case 2:
                for (int i = 0; i < N; i++) {
                    for (int j = N-1; j >= 0; j--) {
    
                        if (block[j][i] != 0) {
                            q.push(block[j][i]);
                            block[j][i] = 0;
                        }
                    }
    
                    int num = 0;
                    int idx = N-1;
    
                    while(!q.empty()) {
                        num = q.front();
                        q.pop();
    
                        if (block[idx][i] == 0) block[idx][i] = num;
                        else if (block[idx][i] == num) {
                            block[idx][i] *= 2;
                            idx--;
                        }
                        else {
                            block[--idx][i] = num;
                        }
                    }
                }
                break;
    
            // 북
            case 3:
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < N; j++) {
    
                        if (block[j][i] != 0) {
                            q.push(block[j][i]);
                            block[j][i] = 0;
                        }
                    }
    
                    int num = 0;
                    int idx = 0;
    
                    while(!q.empty()) {
                        num = q.front();
                        q.pop();
    
                        if (block[idx][i] == 0) block[idx][i] = num;
                        else if (block[idx][i] == num) {
                            block[idx][i] *= 2;
                            idx++;
                        }
                        else {
                            block[++idx][i] = num;
                        }
                    }
                }
                break;
        }
    }
    
    
    void dfs(int depth) {
       
        // 5번 이동 시 return
        if (depth == 5) {
    
            for (int i = 0; i < N; i++)
                for (int j = 0; j < N; j++)
                    ans = max(ans, block[i][j]); // Max값 찾기
    
            return;
        }
    
        int copyBlock[MAX_SIZE][MAX_SIZE];
    
        copy(copyBlock, block); // block을 copyBlock에 복
    
        // 동 서 남 북 이동
        for (int i = 0; i < 4; i++) {
            move(i);
            dfs(depth + 1); // 이동 시 depth 증가
            copy(block, copyBlock); // copyBlock을 block에 복사
        }
    }
    
    int main() {
    
        ios_base::sync_with_stdio(false);
        cin.tie(0);
    
        cin >> N;
    
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                cin >> block[i][j];
            }
        }
    
        dfs(0);
    
        cout << ans;
        return 0;
    }

     

    리뷰

    • 문제 제목만 Easy다. 풀이는 전혀 Easy하지 않다.
    • 모든 탐색이 필요해 DFS를 사용해 동, 서, 남, 북 탐색을 하였다.
    • block[i][j] 수를 한 줄씩 idx 순서대로 큐에 넣고, idx를 순회하며 큐의 front와 같은 수가 있는 지 확인한다. 있다면 합쳐진다.
    • 모든 DFS가 끝나고 array 중 MAX 값을 찾아 리턴한다.

    해당 문제 링크

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

     

    12100번: 2048 (Easy)

    첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며, 이외의 값은 모두 블록을 나타낸다. 블록에 쓰여 있는 수는 2보다 크거나 같고, 1024보다 작거나 같은 2의 제곱꼴이다. 블록은 적어도 하나 주어진다.

    www.acmicpc.net

     

    댓글

Designed by black7375.