본문 바로가기

BOJ/C++

[BOJ] 12094. 2048(Hard)

*2048(easy)와 풀이단계는 비슷하지만, 가지치기를 해줘야 한다. (최대 횟수가 2배로 늘었기 때문에)

-가지치기

1) 변경된 맵이 변경되기 이전의 맵과 동일한 경우 -> 이 방향으로는 더 이상 나아가지 않는다. 

2) 맵에서 최대값을 찾을때, 최대값은 2승씩 커진다. (cnt==10 이라면 가장 최대값은 1024가 될 것이다. )

이 특징을 이용해서 현재 depth에서 최대값에 도달할 수 있는 지 확인한다.

(즉, 한 번 10번까지 변경된 맵에서 최대값을 추출한 후 maxBlock[10] = 1024 / maxBlock[9] = 512 .... 이런 식으로 미리 저장을 해 놓는다.)

*실제 최대값은 1024가 아닐 수 있다. 

3) 현재 맵에서 구한 최대값이 현재 depth(==cnt)에서 나와야 하는 최대값보다 작은 경우에는 더 이상 보지 않는다. 

 

*가지치기 1번 때문에 맵을 먼저 변경한 후에 dfs를 돌리도록 변경했다. 

쉬운 버전 참고

2019/08/01 - [BOJ/C++] - [BOJ] 12100. 2048(easy)

 

[BOJ] 12100. 2048(easy)

[문제] https://www.acmicpc.net/problem/12100 12100번: 2048 (Easy) 첫째 줄에 보드의 크기 N (1 ≤ N ≤ 20)이 주어진다. 둘째 줄부터 N개의 줄에는 게임판의 초기 상태가 주어진다. 0은 빈 칸을 나타내며,..

jayrightthere.tistory.com

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
/*
BOJ 12094. 2048 hard
*/
 
using namespace std;
 
int n, ans = 0;
int maxBlock[11];
 
int map[21][21] = { {0} };
 
//void print(int(*map)[21]) {
//
//  cout << '\n';
//  for (int i = 0; i < n; i++) {
//      for (int j = 0; j < n; j++) {
//          cout << map[i][j] << ' ';
//      }
//      cout << '\n';
//  }
//  cout << '\n';
//}
bool check(int(*chk)[21]) {
    //이전의 것과 같은 지 확인한다.
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (chk[i][j] != map[i][j]) return false;
        }
    }
    return true;
}
void moveBlocks(int dir) {
    //방향에 따라서 이동
    //다음 호출 함수로 넘길 맵
    int c_map[21][21] = { {0} };
 
    vector<int> combine, list;
 
    int tmp = 0;
    for (int i = 0; i < n; i++) {
        list.clear();
        combine.clear(); //현재 행에 저장될 숫자들을 저장
 
        for (int j = 0; j < n; j++) {
            if (dir <= 1) {
                //북 남
                if (map[j][i]) list.push_back(map[j][i]);
            }
            else {
                if (map[i][j]) list.push_back(map[i][j]);
            }
        }
        //동, 남의 경우에는 리버스한다.
        if (dir == 1 || dir == 3) {
            reverse(list.begin(), list.end());
        }
 
        for (int j = 0; j < list.size(); j++) {
            if (j != list.size() - 1 && list[j] == list[j + 1]) {
                combine.push_back(list[j] * 2);
                j++;
            }
            else combine.push_back(list[j]);
        }
        //이제 순서대로 넣는다.
 
        //방향에 맞게 c_map에 넣는다.
        for (int j = 0; j < combine.size(); j++) {
            if (dir == 0) {
                //북->위에서부터 채운다.
                c_map[j][i] = combine[j];
            }
            else if (dir == 1) {
                c_map[n - j - 1][i] = combine[j];
            }
            else if (dir == 2) {
                //서
                c_map[i][j] = combine[j];
            }
            else if (dir == 3) {
                c_map[i][n - j - 1] = combine[j];
            }
 
        }
    }
    memcpy(map, c_map, sizeof(map));
}
void dfs(int cnt) {
 
    int max = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            max = max > map[i][j] ? max : map[i][j];
        }
    }
    if (max <= maxBlock[cnt]) return; //합쳐도 더 커질 가능성이 없는 depth
 
    if (cnt == 10) {
        ans = ans > max ? ans : max;
 
        int tmp = ans;
        while (cnt > 0) {
            maxBlock[cnt--] = tmp;
            tmp /= 2;
        }
        return;
    }
 
    int c_map[21][21];
    memcpy(c_map, map, sizeof(map));
 
    for (int k = 0; k < 4; k++) {
         
        moveBlocks(k);
        if (check(c_map)) continue;
        dfs(cnt + 1);
        memcpy(map, c_map, sizeof(map));
    }
}
int main() {
 
    ios_base::sync_with_stdio(0);
    cin.tie(0);
 
    cin >> n;
 
    int max = 0;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> map[i][j];
            ans = ans > map[i][j] ? ans : map[i][j];
        }
    }
 
    dfs(0);
 
    cout << ans << '\n';
    return 0;
}

'BOJ > C++' 카테고리의 다른 글

[BOJ] 2151. 거울설치 + TC  (0) 2020.03.18
[BOJ] 9376. 탈옥  (0) 2020.03.18
[BOJ] 16638. 괄호 추가하기2  (0) 2020.03.17
[BOJ] 16988. Baaaaaaaaaduk2 (Easy)  (0) 2020.03.16
[BOJ] 10711. 모래성  (0) 2020.03.15