반응형

문제 링크: https://www.acmicpc.net/problem/12094

 

12094번: 2048 (Hard)

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

www.acmicpc.net

<문제 풀이> 백트랙킹

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

 

12100번: 2048 (Easy)

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

www.acmicpc.net

2048 Easy 문제에서 백트랙킹이 추가된 문제이다.

 

1. 이동 후 항상 변화가 있어야 한다. (이동 후 배열의 값이 바뀌었는지 체크)

2 4 8

2 4 8 

2 4 8

에서 left를 하면

2 4 8

2 4 8

2 4 8

변화가 없는 상태에서 계속 연산을 해봤자 의미가 없다. 

-> 최대 k 번까지 이동했을 때 최댓값을 구하고 싶은 거니깐 항상 변화가 있어야 한다.

 

2. k번 이동했을 때 현재 배열의 값으로 10번까지 이동해서 만들 수 있는 최댓값이 지금 까지 갱신한 최댓값 이하이면  더 이상 진행하지 않는다.

1번 이동했을 때 현재 배열의 값의 최대값이 2라면

10번 이동했을 때 현재 배열의 최댓값으로 만들 수 있는 수는 2048이다.

2 * 2 ^ (10 - 1) = 1024  -> ( 현재 배열의 값의 최대값 * 2^(10 - k) ) 

그런데 지금까지 갱신한 최댓값이 4096이라면

아무리 최고의 상황이 나오더라도 10번까지 이동해서 4096을 만들 수 없다

 

 

<C++ 소스 코드>

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
int N;
int board[20][20];
bool visited[20][20];
int res = 0;
int max_res = 0;
void printBoard() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cout << board[i][j] << ' ';
        }
        cout << '\n';
    }
    cout << "\n\n";
}
 
void rotate() {
    int temp[20][20];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            temp[i][j] = board[i][j];
        }
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            board[i][j] = temp[N - j - 1][i];
        }
    }
}
 
 
void left() {
    for (int i = 0; i < N; i++) {
        int moved[20= { 0, };
        bool combined[20= { 0, };
        int idx = 0;
        for (int j = 0; j < N; j++) {
            if (board[i][j] == 0continue;
            if (moved[idx] == 0) {
                moved[idx] = board[i][j];
            }
            else if (moved[idx] && combined[idx]) {
                moved[++idx] = board[i][j];
            }
            else if (moved[idx] == board[i][j]){
                moved[idx] *= 2;
                combined[idx++= true;
           
            }
            else {
                moved[++idx] = board[i][j];
            }
 
            
        }
        for (int j = 0; j < N; j++) {
            board[i][j] = moved[j];
        }
    }
}
 
void up() {
    rotate();
    rotate();
    rotate();
    left();
    rotate();
}
void right() {
    rotate();
    rotate();
    left();
    rotate();
    rotate();
 
}
 
void down() {
    rotate();
    left();
    rotate();
    rotate();
    rotate();
}
 
void tempToBoard(int temp[][20]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            board[i][j] = temp[i][j];
        }
    }
}
 
bool isChanged(int arr1[][20], int arr2[][20]) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (arr1[i][j] != arr2[i][j]) return true;
        }
    }
    return false;
}
 
void dfs(int k) {
    int temp[20][20];
    int cur_max = 0;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            temp[i][j] = board[i][j];
            if (board[i][j] >= cur_max) cur_max = board[i][j];
        }
    }
    res = max(res, cur_max);
 
    if (k == 10return;
    if (cur_max * 1 << (10 - k) <= res) return;
 
    left();
    if (isChanged(temp, board)) {
        dfs(k + 1);
        tempToBoard(temp);
    }
    right();
    if (isChanged(temp, board)) {
        dfs(k + 1);
        tempToBoard(temp);
    }
    up();
    if (isChanged(temp, board)) {
        dfs(k + 1);
        tempToBoard(temp);
    }
    down();
    if (isChanged(temp, board)) {
        dfs(k + 1);
        tempToBoard(temp);
    }
 
 
 
 
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    cin >> N;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> board[i][j];
            if (board[i][j] >= max_res) max_res = board[i][j];
        }
    }
    
    dfs(0);
    cout << res;
   
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 11559번] Puyo Puyo  (0) 2022.01.13
[백준 15686번] 치킨 배달  (0) 2022.01.09
[백준 12100번] 2048(Easy)  (0) 2022.01.05
[백준 18808번] 스티커 붙이기  (0) 2022.01.05
[백준 2636번] 치즈  (0) 2022.01.05
반응형

문제 링크: https://www.acmicpc.net/problem/12100

 

12100번: 2048 (Easy)

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

www.acmicpc.net

<문제 풀이> 시뮬레이션

4가지 이동방향을 구현한 뒤 DFS로 4가지 방향에 대한 모든 경우의 수를 구하면 된다.

한 가지 방향만 잘 구현하면 나머지는 비슷하기에 금방 구현할 수 있다.

 

up방향을 구현할 때 그냥 각 열에 원소를 맨 위 원소부터 시작해서 하나씩 잡고 위로 당겨보면 된다. 

 

 

<C++ 소스 코드>

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
int N;
int board[20][20];
bool visited[20][20];
int res = 0;
void printBoard() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cout << board[i][j] << ' ';
        }
        cout << '\n';
    }
    cout << "\n\n";
}
 
void up() {
    for (int i = 1; i < N; i++) {
        for (int j = 0; j < N; j++) {
            for (int k = i; k >= 1; k--) {
                if (board[k][j] == 0)break;
                if (board[k - 1][j]) {
                    if (!visited[k - 1][j] && board[k-1][j] == board[k][j]) {
                        board[k - 1][j] *= 2;
                        board[k][j] = 0;
                        visited[k - 1][j] = true;
                    }
                    break;
                }
                else {
                    board[k - 1][j] = board[k][j];
                    board[k][j] = 0;
                }
            }
 
        }
    }
    fill(&visited[0][0], &visited[19][20], 0);
}
 
void down() {
    for (int i = N-2; i >=0; i--) {
        for (int j = 0; j < N; j++) {
            for (int k = i; k <= N-2; k++) {
                if (board[k][j] == 0)break;
                if (board[k + 1][j]) {
                    if (!visited[k + 1][j] && board[k + 1][j] == board[k][j]) {
                        board[k + 1][j] *= 2;
                        board[k][j] = 0;
                        visited[k + 1][j] = true;
                    }
                    break;
                }
                else {
                    board[k + 1][j] = board[k][j];
                    board[k][j] = 0;
                }
            }
 
        }
    }
    fill(&visited[0][0], &visited[19][20], 0);
}
void left() {
    for (int j = 1; j < N; j++) {
        for (int i = 0; i < N; i++) {
            for (int k = j; k >= 1; k--) {
                if (board[i][k] == 0)break;
                if (board[i][k-1]) {
                    if (!visited[i][k-1&& board[i][k-1== board[i][k]) {
                        board[i][k-1*= 2;
                        board[i][k] = 0;
                        visited[i][k-1= true;
                        
                    }
                    break;
                    
                }
                else {
                    board[i][k-1= board[i][k];
                    board[i][k] = 0;
                }
            }
        }
    }
    fill(&visited[0][0], &visited[19][20], 0);
}
 
void right() {
    for (int j = N-2; j >=0; j--) {
        for (int i = 0; i < N; i++) {
            for (int k = j; k <= N-2; k++) {
                if (board[i][k] == 0)break;
                if (board[i][k + 1]) {
                    if (!visited[i][k + 1&& board[i][k + 1== board[i][k]) {
                        board[i][k + 1*= 2;
                        board[i][k] = 0;
                        visited[i][k + 1= true;
                    }
                    break;
                }
                else {
                    board[i][k + 1= board[i][k];
                    board[i][k] = 0;
                }
            }
        }
    }
    fill(&visited[0][0], &visited[19][20], 0);
}
void dfs(int k) {
    if (k == 5) {
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                res = max(res, board[i][j]);             
            }
        }
        return;
    }
    int temp[20][20];
 
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            temp[i][j] = board[i][j];
        }
    }
    up();
    dfs(k + 1);
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            board[i][j] = temp[i][j];
        }
    }
    left();
    dfs(k + 1);
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            board[i][j] = temp[i][j];
        }
    }
    down();
    dfs(k + 1);
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            board[i][j] = temp[i][j];
        }
    }
    right();
    dfs(k + 1);
    for (int i = 0; i < 20; i++) {
        for (int j = 0; j < 20; j++) {
            board[i][j] = temp[i][j];
        }
    }
 
}
 
 
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> N;
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cin >> board[i][j];
        }
    }
 
    dfs(0);
    cout << res;
  
    return 0;
}
 
 
cs

 

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 15686번] 치킨 배달  (0) 2022.01.09
[백준 12094번] 2048 (Hard)  (0) 2022.01.08
[백준 18808번] 스티커 붙이기  (0) 2022.01.05
[백준 2636번] 치즈  (0) 2022.01.05
[백준 15683번] 감시  (1) 2022.01.04
반응형

문제 링크: https://www.acmicpc.net/problem/18808

 

18808번: 스티커 붙이기

혜윤이는 최근에 다양한 대회를 참여하면서 노트북에 붙일 수 있는 스티커들을 많이 받았다. 스티커는 아래와 같이 사각 모눈종이 위에 인쇄되어 있으며, 스티커의 각 칸은 상하좌우로 모두 연

www.acmicpc.net

<문제 풀이> 시뮬레이션

이 문제는 배열을 회전하는 것만 잘 구현하면 되는 문제이다.

 

배열을 그려서 규칙을 잘 보면 X행에 있는 모든 원소는 90도 회전하면 Y열로 이동하고,

row, col 값이 서로 바뀐다

 

/*idx 번째 스티커를 1회전*/
void rotate(int idx) {
    int temp[10][10];
    for (int x = 0; x < R[idx]; x++) {
        for (int y = 0; y < C[idx]; y++) {
            temp[x][y] = sticker[idx][x][y];
        }
    }
    swap(R[idx], C[idx]);
    for (int x = 0; x < R[idx]; x++) {
        for (int y = 0; y < C[idx]; y++) {
            sticker[idx][x][y] = temp[C[idx] - 1 - y][x];
        }
    }
}

 

배열 회전만 구현하면 나머지는 문제 조건 그대로 구현하면 끝이다.

 

 

<C++ 소스 코드>

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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
int N, M, K;
 
int sticker[100][10][10];
bool notebook[40][40];
int R[100];
int C[100];
 
 
/*idx 번째 스티커를 1회전*/
void rotate(int idx) {
    int temp[10][10];
    for (int x = 0; x < R[idx]; x++) {
        for (int y = 0; y < C[idx]; y++) {
            temp[x][y] = sticker[idx][x][y];
        }
    }
    swap(R[idx], C[idx]);
    for (int x = 0; x < R[idx]; x++) {
        for (int y = 0; y < C[idx]; y++) {
            sticker[idx][x][y] = temp[C[idx] - 1 - y][x];
        }
    }
}
 
/*idx번째 스티커를 붙여본다 성공 true, 실패 false*/
bool solve(int idx) {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            bool flag = true;
            for (int x = 0; x < R[idx]; x++) {
                if (!flag)break;
                for (int y = 0; y <C[idx]; y++) {
                    if (sticker[idx][x][y] == 0)continue;
                    if (i + x >= N || j + y >= M) { // 범위를 벗어나면 실패
                        flag = false;
                        break;
                    }
                    if (notebook[i + x][j + y]) { //이미 스티커가 붙어있으면 실패
                        flag = false;
                        break;
                    }
                }
            }
            if (flag) { // 스티커를 붙일 수 있으면
                for (int x = 0; x < R[idx]; x++) {
                    for (int y = 0; y < C[idx]; y++) {
                        if (sticker[idx][x][y] == 0)continue;
                        notebook[i + x][j + y] = true;
                    }
                }
                return true;
            }
 
        }
 
    }
    return false;
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> N >> M >> K;
 
    for (int i = 0; i < K; i++) {
        cin >> R[i] >>C[i];
        for (int x = 0; x < R[i]; x++) {
            for (int y = 0; y < C[i]; y++) {
                cin >> sticker[i][x][y];
            }
        }
    }
    
    for (int i = 0; i < K; i++) {
        for (int rotate_cnt = 0; rotate_cnt < 4; rotate_cnt++) {
            if(solve(i)) break;
            rotate(i);
        }
    }
    int cnt = 0;
    for (int i = 0; i < N; i++) {
        for (int j =0; j < M; j++) {
            if (notebook[i][j])cnt++;
        }
    }
    cout << cnt;
 
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 12094번] 2048 (Hard)  (0) 2022.01.08
[백준 12100번] 2048(Easy)  (0) 2022.01.05
[백준 2636번] 치즈  (0) 2022.01.05
[백준 15683번] 감시  (1) 2022.01.04
[백준 1987번] 알파벳  (0) 2022.01.03
반응형

문제 링크: https://www.acmicpc.net/problem/2636

 

2636번: 치즈

아래 <그림 1>과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(<그림 1>에서 네모 칸에 X친 부분)에는 치즈가 놓

www.acmicpc.net

<문제 풀이> BFS

X로 표시된 곳엔 치즈가 없으니깐 X로 표시된 곳 중 한 곳에서 공기가 출발한다고 생각하고 BFS를 돌리면서 공기와 치지를 접촉시켜 보면 됩니다.

 

1. 공기는 이미 방문했던 곳을 다시 방문할 필요가 없다

2. 공기가 접촉한 적이 없는 치즈를 만나면 그곳을 한 시간 후 녹을 치즈로 바꾸고('c') 방문 체크를 합니다.

-> 그리고 한 시간 후 공기는 이 위치에서 다시 BFS를 진행하도록 임시 큐에 해당 좌표를 넣습니다.

-> 치즈가 녹으면 결국 그곳엔 공기가 생김 

 

 

<C++ 소스 코드>

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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
#define X first
#define Y second
 
int dx[4= {0-101}; //0 == right, 1 == up, 2 == left, 3 == down
int dy[4= {10-10};
 
int n, m;
 
int cheeze[100][100];
bool visited[100][100];
void AirBFS() {
    queue<pair<intint> > Q;
    Q.push({ 00 });
    visited[0][0= true;
    int time = 0// 걸린 시간
    int last_cnt = 0//마지막 녹기 한 시간 전에 남아있는 치즈 조각의 수 
    while (true) {
        queue<pair<intint> > temp;
        bool flag = false//한 시간 후 녹일 치즈가 있다면 true
        int cnt = 0// 한 시간 후 녹일 치즈의 개수
        while (!Q.empty()) {
            auto cur = Q.front(); Q.pop();
            for (int dir = 0; dir < 4; dir++) {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];
                if (nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
                if (visited[nx][ny] || cheeze[nx][ny] == 'c'continue// 이미 방문했거나 치즈가 공기에 접촉했으면 무시
                if (cheeze[nx][ny] == 1) { // 공기에 접촉하지 않은 치즈이면
                    flag = true
                    cheeze[nx][ny] = 'c'// 한 시간 후 치즈를 녹인다.
                    cnt++// 한 시간 후 녹일 치즈의 개수 증가
                    temp.push({ nx, ny }); // 공기는 한 시간 후 녹을 치즈의 위치에서 다시 시작
                    visited[nx][ny] = true;
                }
                else { // 빈 공간이면 그냥 이동
                    Q.push({ nx, ny });
                    visited[nx][ny] = true;
                }
            }
        }
        if (!flag) { //한 시간 후 녹일 치즈가 없다면
            cout << time << '\n' << last_cnt;
            break;
        }
        last_cnt = cnt; //가장 최근에 녹인 치즈의 개수
        time++// 한 시간 뒤
        Q = temp;
    }
}
 
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> cheeze[i][j];
        }
    }
    AirBFS();
    
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 12100번] 2048(Easy)  (0) 2022.01.05
[백준 18808번] 스티커 붙이기  (0) 2022.01.05
[백준 15683번] 감시  (1) 2022.01.04
[백준 1987번] 알파벳  (0) 2022.01.03
[백준 18809번] Gaaaaaaaaaarden  (0) 2022.01.02
반응형

문제 링크: https://www.acmicpc.net/problem/15683

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감

www.acmicpc.net

<문제 풀이> 시뮬레이션

1번 cctv부터 n번 cctv까지 한 번씩 회전시켜보면서 모든 경우의 수를 다 해보면 되는 완전 탐색 문제입니다.

 

문제는 방향을 어떻게 처리할까 인데 각 CCTV의 방향을 분리해서 생각해보면 쉽게 문제를 해결할 수 있습니다.

 

int dx[4= {0-101}; //0 == right, 1 == up, 2 == left, 3 == down
int dy[4= {10-10};
 
dfs, bfs에서 위와 같이 4방향을 나타내는데 각 인덱스의 의미는 아래와 같습니다.
0번 인덱스는 오른쪽 방향
1번 인덱스는 위쪽 방향
2번 인덱스는 왼쪽 방향
3번 인덱스는 아래쪽 방향
 
 

 

이제 cctv로 방향을 표현해보겠습니다
1번 2번 3번 4번 5번

1번 cctv : right ( 0 index)

2번 cctv: left  + right (2 index + 0 index)

3번 cctv: up + right (1 index + 0 index)

4번 cctv: left + up + right (2 index + 1 index + 0 index)

5번 cctv: down + left + up + right (3 index + 2 index + 1 index + 0 index)

 

이제 cctv로 감시구역을 체크할 때 cctv의 방향을 분리해서 한 방향씩 검사를 해보면 됩니다.

그리고 회전할 때는 방향 인덱스의 값을 +1 해주면 끝입니다. 

/*dir 1증가하면 90도 회전*/
        if (cctv[x][y] == 1) {
            check(x, y, dir); //dir == 0 일때 right
        }
        else if (cctv[x][y] == 2) { 
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 2); //dir == 0 일때 left
 
        }
        else if (cctv[x][y] == 3) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
        }
        else if (cctv[x][y] == 4) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
            check(x, y, dir + 2); //dir == 0 일때 left
 
        }
        else if (cctv[x][y] == 5) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
            check(x, y, dir + 2); //dir == 0 일때 left
            check(x, y, dir + 3); //dir == 0 일때 down

 

        }
        solve(idx + 1); //다음 cctv 회전시키기
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                cctv[i][j] = backup[i][j];
            }
        }

 

 

 

 

<C++ 소스 코드>

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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
int dx[4= {0-101}; //0 == right, 1 == up, 2 == left, 3 == down
int dy[4= {10-10};
 
int N, M;
int cctv[8][8]; // 0 빈칸, 1 ~ 5 cctv, 6 벽
vector<pair<intint> > cctv_pos;
int res = 64;
 
 
//x,y에 위치한 cctv가 dir방향을 감시
void check(int x, int y, int dir) {
    dir %= 4//가능한 감시방향 right, up, left, down (0 ~ 3)
    while (true) {
        int nx = x + dx[dir];
        int ny = y + dy[dir];
        x = nx;
        y = ny;
        if (nx < 0 || ny < 0 || nx >= N || ny >= M)return;
        if (cctv[nx][ny] == 6return;
        if (cctv[nx][ny] != 0continue;
        cctv[nx][ny] = '#';
    }
}
 
 
//idx번째 cctv를 회전
void solve(int idx) {
    int cctv_cnt = cctv_pos.size();
    if (idx == cctv_cnt) { //모든 cctv를 다 확인했을 때
        int temp_res = 0;
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                if (cctv[i][j] == 0) temp_res++;
            }
        }
        res = min(res, temp_res);
        return;
    }
    int x = cctv_pos[idx].first;
    int y = cctv_pos[idx].second;
    int backup[8][8];
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            backup[i][j] = cctv[i][j];
        }
    }
    for (int dir = 0; dir < 4; dir++) { //4번까지 회전시켜본다
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                backup[i][j] = cctv[i][j];
            }
        }
        /*dir 1증가하면 90도 회전*/
        if (cctv[x][y] == 1) {
            check(x, y, dir); //dir == 0 일때 right
        }
        else if (cctv[x][y] == 2) { 
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 2); //dir == 0 일때 left
 
        }
        else if (cctv[x][y] == 3) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
        }
        else if (cctv[x][y] == 4) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
            check(x, y, dir + 2); //dir == 0 일때 left
 
        }
        else if (cctv[x][y] == 5) {
            check(x, y, dir); //dir == 0 일때 right
            check(x, y, dir + 1); //dir == 0 일때 up
            check(x, y, dir + 2); //dir == 0 일때 left
            check(x, y, dir + 3); //dir == 0 일때 down
        }
        solve(idx + 1); //다음 cctv 회전시키기
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < M; j++) {
                cctv[i][j] = backup[i][j];
            }
        }
    }
}
 
 
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> N >> M;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> cctv[i][j];
            if (cctv[i][j] >= 1 && cctv[i][j] <= 5) {
                cctv_pos.push_back({ i, j });     
            }
        }
    }
    solve(0);
    cout << res;
    
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 18808번] 스티커 붙이기  (0) 2022.01.05
[백준 2636번] 치즈  (0) 2022.01.05
[백준 1987번] 알파벳  (0) 2022.01.03
[백준 18809번] Gaaaaaaaaaarden  (0) 2022.01.02
[백준 1799번] 비숍  (0) 2021.12.31
반응형

문제 링크: https://www.acmicpc.net/problem/1987

 

1987번: 알파벳

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의 한 칸으

www.acmicpc.net

<문제 풀이> DFS, 백트랙킹

DFS로 갈 수 있는 최장 거리를 구하면 되는데 방문한 좌표로 방문 체크를 하는게 아니라 알파벳 사용여부로 방문체크를  해야 된다.


visited[26];

->알파벳 'A' ~  'Z' 각각에 'A'를 빼주면 0 ~ 25의 값에 대응시킬 수 있다

 

 

<C++ 소스 코드>

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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
char board[20][20];
 
int R, C;
 
bool visited[26]; // A ~ Z ( 0 ~ 25)
int dx[4= {001-1};
int dy[4= {1-100};
int res = 1;
void dfs(int x, int y, int depth) {
    for (int dir = 0; dir < 4; dir++) {
        int nx = x + dx[dir];
        int ny = y + dy[dir];
        if (nx < 0 || ny < 0 || nx >= R || ny >= C)continue;
        if (visited[board[nx][ny] - 'A'])continue;
        visited[board[nx][ny] - 'A'= true;
        res = max(res, depth + 1);
        dfs(nx, ny, depth + 1);
        visited[board[nx][ny] - 'A'= false;
    }
}
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> R >> C;
    for (int i = 0; i < R; i++) {
        for (int j = 0; j < C; j++) {
            cin >> board[i][j];
        }
    }
    visited[board[0][0- 'A'= true;
    dfs(001);
 
    cout << res;
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 2636번] 치즈  (0) 2022.01.05
[백준 15683번] 감시  (1) 2022.01.04
[백준 18809번] Gaaaaaaaaaarden  (0) 2022.01.02
[백준 1799번] 비숍  (0) 2021.12.31
[백준 1941번] 소문난 칠공주  (0) 2021.12.31
반응형

문제 링크: https://www.acmicpc.net/problem/18809

 

18809번: Gaaaaaaaaaarden

첫째 줄에 정원의 행의 개수와 열의 개수를 나타내는 N(2 ≤ N ≤ 50)과 M(2 ≤ M ≤ 50), 그리고 초록색 배양액의 개수 G(1 ≤ G ≤ 5)와 빨간색 배양액의 개수 R(1 ≤ R ≤ 5)이 한 칸의 빈칸을 사이에 두

www.acmicpc.net

<문제 풀이> 백트랙킹

1. 배양액을 뿌릴 수 있는 땅에 대해서 같은 것이 있는 순열(RRRGG...)을 구한다.

2. 뽑은 수열에 대해서 큐 두 개를 준비해서 빨간색 배양액, 초록색 배양액을 동시에 BFS를 진행한다.

-> 큐에는 항상 같은 레벨(같은 초)의 좌표가 들어간다.

-> BFS를 진행할 때 매 초마다  빨간색 배양액과 초록색 배양액이 동일한 시간에 만나는지 체크

-> 구현상 큐에는 꽃이 피어난 좌표도 들어갈 수 있으므로 현재 좌표가 꽃이 피어난 좌표이면 무시

 

<C++ 소스 코드>

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
#define X first
#define Y second
 
int dx[4= {0 , 01-1};
int dy[4= { 1-100 };
 
int N, M, G, R;
int G_temp, R_temp;
int board[50][50];
int backup[50][50]; //board 백업용
int visited[50][50]; //배양액 방문 체크 -> 1 == R, 2 == G
int R_visited[50][50]; //R배양액 BFS 방문 체크
int G_visited[50][50]; //G배양액 BFS 방문 체크
int res = 0// 꽃의 최대 개수
 
 
//R배양액, G배양액 퍼트리기
void BFS() {
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            backup[i][j] = board[i][j]; //board 배열을 다시 사용하기 위해 백업
        }
    }
    queue<pair<intint> > red, green;
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (visited[i][j] == 1) { //R 배양액이면
                red.push({ i, j });
                R_visited[i][j] = true;
            }
            else if (visited[i][j] == 2) { // G 배양액이면
                green.push({ i, j });
                G_visited[i][j] = true;
            }
        }
    }
 
    int cnt = 0//꽃의 개수
    while (!red.empty() || !green.empty()) {
 
        int red_size = red.size();
        for (int i = 0; i < red_size; i++) {
            auto cur = red.front(); red.pop();
            if (board[cur.X][cur.Y] == 3continue//만약 꽃이 피어난 곳이면 무시
            for (int dir = 0; dir < 4; dir++) {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];
                if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                if (R_visited[nx][ny] || board[nx][ny] == 0)continue//방문했거나 호수이면 무시
                if (board[nx][ny] == 3)continue// 꽃이 피어난 곳은 무시
                if (G_visited[nx][ny] && G_visited[nx][ny] != R_visited[cur.X][cur.Y] + 1)continue//배양액은 서로 다른 곳에 뿌려져야한다.
                else if (G_visited[nx][ny] && G_visited[nx][ny] == R_visited[cur.X][cur.Y] + 1) {//만약 동일한 시간에 두 배양액이 합쳐지면
                    board[nx][ny] = 3;  //꽃이 피어난다.
                    cnt++;
                    R_visited[nx][ny] = R_visited[cur.X][cur.Y] + 1;
                    continue;
                }
                R_visited[nx][ny] = R_visited[cur.X][cur.Y] + 1;
                red.push({ nx, ny });
            }
        }
 
        int green_size = green.size();
        for (int i = 0; i < green_size; i++) {
            auto cur = green.front(); green.pop();
            if (board[cur.X][cur.Y] == 3continue//만약 꽃이 피어난 곳이면 무시
            for (int dir = 0; dir < 4; dir++) {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];
                if (nx < 0 || ny < 0 || nx >= N || ny >= M)continue;
                if (G_visited[nx][ny] || board[nx][ny] == 0)continue//방문했거나 호수이면 무시
                if (board[nx][ny] == 3)continue// 꽃이 피어난 곳은 무시
                if (R_visited[nx][ny] && R_visited[nx][ny] != G_visited[cur.X][cur.Y] + 1)continue//배양액은 서로 다른 곳에 뿌려져야한다.
                else if (R_visited[nx][ny] && R_visited[nx][ny] == G_visited[cur.X][cur.Y] + 1) {//만약 동일한 시간에 두 배양액이 합쳐지면
                    board[nx][ny] = 3;  //꽃이 피어난다.
                    cnt++;
                    G_visited[nx][ny] = G_visited[cur.X][cur.Y] + 1;
                    continue;
                }
                G_visited[nx][ny] = G_visited[cur.X][cur.Y] + 1;
                green.push({ nx, ny });
            }
        }
    }
 
    res = max(res, cnt); //최대 꽃의 개수 
 
    /*초기화*/
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            board[i][j] = backup[i][j];
            R_visited[i][j] = 0;
            G_visited[i][j] = 0;
        }
    }
}
 
//N*N 격자에서 초록색 배양액 G개, 빨간색 배양액 R개를 뽑는 조합
void dfs(int cur, int k) {
    if (k == G + R) { //초록색 배양액 G개, 빨간색 배양액 R개를 뿌렸으면
        BFS();
        return;
    }
    for (int i = cur + 1; i < N * M; i++) {
        int x = i / M;
        int y = i % M;
        if (board[x][y] == 2) { // 배양액을 뿌릴 수 있으면
            if (R_temp != 0) { // R 배양액을 다 못뿌렸으면
                R_temp--;
                visited[x][y] = 1;
                dfs(i, k + 1);
                visited[x][y] = 0;
                R_temp++;
            }
            if (G_temp != 0) { // G 배양액을 다 못뿌렸으면 
                G_temp--;
                visited[x][y] = 2;
                dfs(i, k + 1);
                visited[x][y] = 0;
                G_temp++;
            }
        }
    }
}
 
 
 
 
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> N >> M >> G >> R;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
    G_temp = G;
    R_temp = R;
    dfs(-10);
    cout << res;
    return 0;
}
 
 
cs

 

반응형

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

[백준 15683번] 감시  (1) 2022.01.04
[백준 1987번] 알파벳  (0) 2022.01.03
[백준 1799번] 비숍  (0) 2021.12.31
[백준 1941번] 소문난 칠공주  (0) 2021.12.31
[백준 16987번] 계란으로 계란치기  (0) 2021.12.30
반응형

문제 링크: https://www.acmicpc.net/problem/1799

 

1799번: 비숍

첫째 줄에 체스판의 크기가 주어진다. 체스판의 크기는 10이하의 자연수이다. 둘째 줄부터 아래의 예와 같이 체스판의 각 칸에 비숍을 놓을 수 있는지 없는지에 대한 정보가 체스판 한 줄 단위로

www.acmicpc.net

 

 

<문제 풀이> 백트랙킹

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

 

9663번: N-Queen

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

www.acmicpc.net

이문제는 9663번 문제와 비슷하게 접근하면 되는데 핵심은 다음 세 가지입니다.

1. 체스판은 흑색, 백색으로 나누어져 있고, 각 비숍은 다른 색깔에 위치한 비숍을 공격할 수 없다.

 

2. 2차원 배열에서 조합

 

3. 2차원 배열에서 윗 방향 대각선은 X + Y, 아랫 방향 대각선은 X - Y + N으로 나타낼 수 있다.

 

흰색, 검은색 판을 구분하는 방법은 2차원 배열에서 x + y 값을 보면 같은 대각선에 존재하면 x +  y 값이 같은 걸 알 수 있습니다. 

 

 

 

 

<C++ 소스 코드>

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
#include <iostream>
#include <string>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <utility>
#include <climits>
#include <cmath>
#include <deque>
#include <cstdlib>
using namespace std;
 
int board[10][10];
bool visited1[20]; //  / 대각선
bool visited2[20]; //  \ 대각선
int n;
int res = 0;
void dfs(int k, int cnt, bool color) { //color == true 흰색, color == false 검은색
    if (k >= n * n) {
        return;
    }
    for (int i = k; i < n * n; i++) {
        int x = i / n;
        int y = i % n;
        if (color && (x + y) % 2 != 0) {//흰색이 아니면
            continue;
        }
        else if(!color && (x + y) % 2 == 0){//검은색이 아니면
            continue;
        }
        if (board[x][y] == 0continue;
        if (visited1[x + y])continue;
        if (visited2[x - y + n])continue;
        visited1[x + y] = true;
        visited2[x - y + n] = true;
        res = max(res, cnt + 1);
        dfs(i + 1 , cnt + 1, color);
        visited1[x + y] = false;
        visited2[x - y + n] = false;
        
    }
}
int main(void) {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
  
    cin >> n;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> board[i][j];
        }
    }
    dfs(00true);
    int temp = res;
    res = 0;
    dfs(10false);
    cout << temp + res;
    return 0;
}
 
 
cs

 

반응형

+ Recent posts