길민호(ethan.mino)
코딩수첩
길민호(ethan.mino)
전체 방문자
오늘
어제
  • 분류 전체보기 (215)
    • Computer Science (0)
    • Web (6)
      • CSS (0)
      • HTML (0)
    • Node.js (0)
    • Javascript (2)
    • Java (46)
      • Spring (27)
      • Jsp (0)
    • C\C++ (2)
    • Programming (0)
    • AI (0)
    • Database (7)
    • Git (5)
    • Algorithm (119)
      • Stack (0)
      • Queue (0)
      • Linked List (0)
      • Sort (0)
      • Simulation (27)
      • Recursion (0)
      • Backtracking (4)
      • Two Pointer (3)
      • Dynamic Programming (19)
      • Greedy (10)
      • Graph (3)
      • Dijkstra (1)
      • BFS\DFS (8)
      • Floyd (1)
      • MST (4)
      • Tree (4)
      • Binary Search (8)
      • Binary Search Tree (4)
    • IntelliJ (4)
    • Vscode (0)
    • Operating System (0)
    • 후기 (3)
    • 성장일지 (13)
    • 스터디 (7)
    • 설치 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • ㅡ

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
길민호(ethan.mino)

코딩수첩

Algorithm/Simulation

[백준 12100번] 2048 (easy) (C/C++)

2022. 3. 17. 01:05

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

 

12100번: 2048 (Easy)

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

www.acmicpc.net


2048 문제는 백트래킹을 이용하여 이동의 모든 경우의 수를 구하고, 큐를 이용하여 각 경우의 수에 대해 가장 큰 블록을 계산하였습니다.

 

아래는 전체 코드입니다.

#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
int board[20][20];

vector<vector<int>> p;    
vector<int> selected(5);

int n; 
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
int ans = 0;

void permutation(int th){   // 6-th개의 이동을 선택하는 모든 경우의 수를 계산하는 함수
    if(th == 6){
        p.push_back(selected);
    }else{
        for(int i = 0; i < 4; i++){ // 0은 상, 1은 하, 2는 좌, 3은 우
            selected[th - 1] = i;
            permutation(th + 1);
        }
    }
}

void game(vector<int> & move){    // 주어진 이동 수열을 기반으로 2048 수행
    int temp[20][20];
    memcpy(temp, board, sizeof(temp));  // 여러 경우의 수에 대해 반복하기 때문에 board를 복사해서 사용

    for(int i = 0; i < move.size(); i++){   // 각각의 이동에 대해 반복
        for(int j = 0; j < n; j++){    // 각각의 행 또는 열에 대해 반복

            pair<int, int> cur; // 위치 또는 값을 변경할 좌표
            // 이동에 따라 시작 지점을 달리함 (ex. ↑인 경우 가장 위의 좌표부터 시작)
            if(move[i] == 0) cur = {0, j}; else if(move[i] == 1) cur = {n-1, j};  
            else if(move[i] == 2) cur = {j, 0}; else if(move[i] == 3) cur = {j, n - 1}; 

            queue<pair<int, int>> empty;    // 비어있는 좌표를 저장하는 큐

            while(true){    // 해당 열 또는 행의 각 좌표에 대해 반복                
                if(cur.x < 0 || cur.y < 0 || cur.x >= n || cur.y >= n) break; 

                if(temp[cur.x][cur.y] == 0){    // 현재 확인 중인 위치가 0인 경우 queue에 삽입
                    empty.push({cur.x, cur.y});
                }else {
                    pair<int, int> nx = {-1, -1}; // 다음 블럭의 좌표
                    for(int k = 1; k < n; k++){ // 다음 블럭의 위치를 찾아서 nx에 저장
                        int x = cur.x + dx[move[i]] * k;
                        int y = cur.y + dy[move[i]] * k;
                        if(x >= 0 && y >= 0 && x < n && y < n && temp[x][y] != 0){
                            nx = {x, y}; break;
                        }
                    }

                    if(nx.x != -1 && nx.y != -1 // 다음 블록이 존재하며, cur와 nx의 값이 같은 경우
                    && temp[cur.x][cur.y] == temp[nx.x][nx.y]){   
                        if(!empty.empty()){ // 빈 곳이 있는 경우
                            pair<int, int> p = empty.front(); empty.pop();  
                            // 값을 두 배로 하여 빈 곳에 블록을 이동시킨다
                            temp[p.x][p.y] = temp[cur.x][cur.y] * 2; 
                            // 현재의 위치를 queue에 넣고, 값을 0으로 변경
                            empty.push({cur.x, cur.y}); temp[cur.x][cur.y] = 0; 
                        }else{  // 빈 곳이 없는 경우
                            temp[cur.x][cur.y] *= 2;    // 값을 두 배로 변경
                        }
                        temp[nx.x][nx.y] = 0;   // 다음 블록의 값을 0으로 변경
                    }else{  // 현재 블럭과 다음 좌표
                        if(!empty.empty()){ // cur를 빈 곳으로 표시하고 빈 곳으로 블럭을 이동시킴
                            pair<int, int> p = empty.front(); empty.pop();
                            temp[p.x][p.y] = temp[cur.x][cur.y];
                            // 현재의 위치를 queue에 넣고, 값을 0으로 변경
                            empty.push({cur.x, cur.y}); temp[cur.x][cur.y] = 0; 
                        }
                        // 빈 곳이 없다면 블럭을 이동시키지도, 값을 변경하지도 않는다.
                    }
                }
                cur = {cur.x + dx[move[i]], cur.y + dy[move[i]]};   // cur의 위치를 한 칸 이동
            }
        }
    }

    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            ans = max(temp[i][j], ans);   
}


int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    cin >> n;
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            cin >> board[i][j];
    
    permutation(1); // 이동의 모든 경우의 수를 구함
    for(auto c : p) game(c);    // 각 경우의 수에 대해 2048 게임 수행

    cout << ans;
}

 

아래는 문제 풀이에 사용된 테스트케이스입니다.

3
2 2 2
0 0 0
0 0 0

3
8 0 0
0 0 0
8 0 0

5
16 8 4 2 0
8 0 0 2 0
4 8 4 0 0
4 0 0 0 0
4 4 0 0 0

'Algorithm > Simulation' 카테고리의 다른 글

[백준 11559번] Puyo Puyo (C/C++)  (0) 2022.03.17
[백준 15686번] 치킨 배달 (C/C++)  (0) 2022.03.17
[백준 18808번] 스티커 붙이기 (C/C++)  (0) 2022.03.16
[백준 14888번] 연산자 끼워넣기 (C/C++)  (0) 2022.03.16
[백준 13335번] 트럭 (C/C++)  (0) 2022.03.16
    'Algorithm/Simulation' 카테고리의 다른 글
    • [백준 11559번] Puyo Puyo (C/C++)
    • [백준 15686번] 치킨 배달 (C/C++)
    • [백준 18808번] 스티커 붙이기 (C/C++)
    • [백준 14888번] 연산자 끼워넣기 (C/C++)
    길민호(ethan.mino)
    길민호(ethan.mino)
    💻 호기심 많은 서버 개발자 길민호입니다.

    티스토리툴바