Skip to content

Commit b79e799

Browse files
committed
알고스팟 : BOARDCOVER2 리뷰
1 parent 206105d commit b79e799

File tree

4 files changed

+264
-1
lines changed

4 files changed

+264
-1
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,4 +664,10 @@ FodyWeavers.xsd
664664
# Additional files built by Visual Studio
665665

666666
# End of https://www.toptal.com/developers/gitignore/api/windows,macos,java,c++,c,visualstudio,intellij
667-
.vscode/
667+
.vscode/
668+
669+
# (추창우) 백준 문제 풀 때 입력을 위한 input.txt 이그노어
670+
**/input.txt
671+
672+
# (추창우) vscode extension인 code runnder 실행시 생기는 파일들 제거
673+
**/tempCodeRunnerFile.cpp

2025-08-28/추창우/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.txt
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <iostream>
2+
#include <vector>
3+
4+
using namespace std;
5+
6+
int boardH, boardW;
7+
int R, C;
8+
char board[10][10];
9+
char block[10][10];
10+
11+
int main(void) {
12+
ios::sync_with_stdio(0);
13+
cin.tie(0);
14+
15+
int cc;
16+
cin >> cc;
17+
for (int c = 0; c < cc; c++) {
18+
cin >> boardH >> boardW >> R >> C;
19+
20+
// 보드 초기화
21+
memset(board, '.', sizeof(board));
22+
23+
for (int i = 0; i < boardH; i++) {
24+
for (int j = 0; j < boardW; j++) {
25+
cin >> board[i][j];
26+
}
27+
}
28+
29+
// 블럭초기화
30+
memset(block, '.', sizeof(block));
31+
32+
for (int i = 0; i < R; i++) {
33+
for (int j = 0; j < C; j++) {
34+
cin >> block[i][j];
35+
}
36+
}
37+
}
38+
39+
return 0;
40+
}
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
#include <algorithm>
2+
#include <cstring> // memset 사용을 위해 추가
3+
#include <iostream>
4+
#include <utility>
5+
#include <vector>
6+
7+
using namespace std;
8+
9+
int boardH, boardW;
10+
int R, C;
11+
char board[10][10];
12+
vector<vector<char>> block;
13+
14+
// 블럭 회전을 위한 값
15+
vector<vector<pair<int, int>>> rotations;
16+
17+
// 가지치기를 위한 block 사이즈
18+
int blockSize = -1;
19+
20+
// 구현 1 : 블럭을 돌리는 과정
21+
// 90도 회전은 행렬연산을 통해서 계산하면 된다
22+
// [ 0 -1 ] [ x ] [ -y ]
23+
// [ 1 0 ] [ y ] [ x ] 자고로 반시계 회전이다
24+
// 원래 좌표에서 x >> -y 로 y >> x로 변환
25+
26+
// 블럭은 계산을 위해 상대 좌표로 표현되어야 한다.
27+
// 첫 번째 만나는 #을 기준으로 얼마나 떨어져있냐를 표현한다.
28+
void makeRotations(vector<vector<char>> &block) {
29+
rotations.clear();
30+
rotations.resize(4);
31+
32+
for (int rot = 0; rot < 4; ++rot) {
33+
int firstX = -1, firstY = -1;
34+
35+
// ★ 현재 회전 상태의 실제 크기를 사용해야 한다 (R,C 사용 금지)
36+
int H = (int)block.size();
37+
int W = H ? (int)block[0].size() : 0;
38+
39+
for (int i = 0; i < H; i++) {
40+
for (int j = 0; j < W; j++) {
41+
// 처음 만난 #을 (0,0)으로 지정하는 상대좌표의 블럭 형태로 변환
42+
if (block[i][j] == '#') {
43+
if (firstY == -1) {
44+
firstY = i;
45+
firstX = j;
46+
}
47+
48+
// 위 캡션에서 설명한대로 상대좌표로 구현
49+
rotations[rot].push_back(make_pair(i - firstY, j - firstX));
50+
}
51+
}
52+
}
53+
54+
// ★ 중복 제거 정확도를 위해 각 회전 모양의 좌표들을 정렬해 정규화한다
55+
sort(rotations[rot].begin(), rotations[rot].end());
56+
57+
// 기존의 블럭을 회전 시킨다.
58+
// 이것은 함수 위의 캡션을 보면 이해가능
59+
vector<vector<char>> dst(W, vector<char>(H, ' '));
60+
for (int i = 0; i < H; ++i) {
61+
for (int j = 0; j < W; ++j) {
62+
dst[j][H - 1 - i] = block[i][j];
63+
}
64+
}
65+
66+
block = dst;
67+
}
68+
69+
// 모든 블럭이 회전된 상태로 넣어졌을 때, 중복된 블럭들을 제거해야한다
70+
sort(rotations.begin(), rotations.end());
71+
rotations.erase(unique(rotations.begin(), rotations.end()), rotations.end());
72+
73+
blockSize = rotations.empty() ? 0 : (int)rotations[0].size();
74+
}
75+
76+
// #, . 로 이루어진 board는 0과 1 그리고 그 이상으로 할 수 있게 구현
77+
int intBoard[10][10];
78+
79+
// 구현 3 : 이 블럭을 둘 수 있는지 확인하는 함수
80+
bool set(int y, int x, const vector<pair<int, int>> &block, int delta) {
81+
int result = true;
82+
83+
for (int i = 0; i < (int)block.size(); i++) {
84+
// ★ 기준 좌표 (y,x)를 반드시 더해 절대좌표로 변환해야 한다
85+
int ny = y + block[i].first;
86+
int nx = x + block[i].second;
87+
88+
// 좌표가 보드를 넘었다면
89+
if (ny >= boardH || ny < 0 || nx >= boardW || nx < 0) {
90+
result = false;
91+
} else if ((intBoard[ny][nx] += delta) >
92+
1) { // 놓았을 때 1 초과 인 것을 검사
93+
result = false;
94+
}
95+
}
96+
97+
return result;
98+
}
99+
100+
// 구현 2: 회전된 블럭들로 board에 블럭을 두기
101+
// 완전 탐색 + 가지치기를 하면서 최대한 빠르게 구해본다.
102+
// 각 상태마다는 두어진 블럭을 가지고 있다.
103+
// 두어진 블럭의 개수가 최대가 되게끔 해보자.
104+
105+
// 모든 경우의 수에서 최고의 답을 저장
106+
int best = -1;
107+
108+
// 가지치기를 구현
109+
// 과대평가를 해서 상한선을 정해야한다.
110+
// 어차피 현재 placed + (남은칸의수)/(블럭) 이 best보다 낮다면 볼 필요도 없다
111+
bool pruning(int placed) {
112+
int empties = 0;
113+
for (int i = 0; i < boardH; i++) {
114+
for (int j = 0; j < boardW; j++) {
115+
if (intBoard[i][j] == 0) {
116+
++empties;
117+
}
118+
}
119+
}
120+
121+
return placed + (empties / blockSize) <= best ? true : false;
122+
}
123+
124+
void search(int placed) {
125+
// 초반에 가지치기를 계산해본다.
126+
if (pruning(placed))
127+
return;
128+
129+
// 비어있는 칸을 찾는다.
130+
int firstY = -1, firstX = -1;
131+
// ★ 보드 순회는 boardH/boardW를 사용해야 한다 (R,C 사용 금지)
132+
for (int i = 0; i < boardH; i++) {
133+
int isBreak = -1;
134+
for (int j = 0; j < boardW; j++) {
135+
if (intBoard[i][j] == 0) {
136+
isBreak = 1;
137+
firstY = i;
138+
firstX = j;
139+
140+
break;
141+
}
142+
}
143+
if (isBreak == 1)
144+
break;
145+
}
146+
147+
// 비어있는 칸이 없으면 종료
148+
if (firstX == -1) {
149+
best = max(best, placed);
150+
return;
151+
}
152+
153+
// 비어있는 칸이 있을 경우 백트래킹을 통한 완전탐색
154+
for (int rot = 0; rot < (int)rotations.size(); ++rot) {
155+
// 둘 수 있는 건지 검사
156+
if (set(firstY, firstX, rotations[rot], 1)) {
157+
// 둘 수 있는경우
158+
search(placed + 1);
159+
}
160+
// 백트래킹 구현
161+
set(firstY, firstX, rotations[rot], -1);
162+
}
163+
164+
// 최대의 개수라고 했으니
165+
// 해당 좌표에 그냥 두지 않았을 경우도 계산해봐야함
166+
intBoard[firstY][firstX] = 1;
167+
search(placed);
168+
intBoard[firstY][firstX] = 0;
169+
}
170+
171+
int solve() {
172+
173+
// board 를 intBoard로 바꾸는 작업 시작
174+
for (int i = 0; i < boardH; ++i) {
175+
for (int j = 0; j < boardW; ++j) {
176+
intBoard[i][j] = board[i][j] == '#' ? 1 : 0;
177+
}
178+
}
179+
best = 0;
180+
search(0);
181+
182+
return best;
183+
}
184+
185+
int main(void) {
186+
ios::sync_with_stdio(0);
187+
cin.tie(0);
188+
189+
int cc;
190+
cin >> cc;
191+
for (int c = 0; c < cc; c++) {
192+
cin >> boardH >> boardW >> R >> C;
193+
194+
// 보드 초기화
195+
memset(board, '.', sizeof(board));
196+
197+
for (int i = 0; i < boardH; i++) {
198+
for (int j = 0; j < boardW; j++) {
199+
cin >> board[i][j];
200+
}
201+
}
202+
203+
// 블럭초기화
204+
block.assign(R, vector<char>(C, '.'));
205+
206+
for (int i = 0; i < R; i++) {
207+
for (int j = 0; j < C; j++) {
208+
cin >> block[i][j];
209+
}
210+
}
211+
makeRotations(block);
212+
cout << solve() << endl;
213+
}
214+
215+
return 0;
216+
}

0 commit comments

Comments
 (0)