문제 링크: https://www.acmicpc.net/problem/19235
어딘가에서 본 문제의 조건과 여기에 있는 문제의 조건이 다른 경우는 그냥 다른 것입니다.
(링크: https://www.acmicpc.net/contest/rule/517)
2020 상반기 삼성 코테 기출이라고 합니다. 줏어듣기로는 문제조건이 약간 다르다는데 코테에서는 2x1짜리 고려 안하고 그냥 밑으로 쭉 내리면 됐다네요 (줏어들은거라 아닐 수도 있음)
일단 초록색 보드만 생각해봅시다. 파란색 보드는 나중에 생각합시다.
1x1, 1x2(세로)의 경우 그냥 밑으로 쭉 내리면서 블록이 나올 때까지 내리면 됩니다
2x1의 경우 밑에 두칸을 봐야됩니다. 두 칸중 하나라도 블록이 채워져있다면 못내립니다.
매 턴은 이렇게 진행합니다
- 블록을 위에서 내림
- 지워지는 행 있는지 확인
- 지워지는 행이 있다면, 그 행 지우고 점수 올리고 그 위 블록들을 잘 내림
그리고 다시 지워지는 행 있는지 확인 -> 또 지우고.. 반복 - 지워지는 행 없으면 나오기
- 지워지는 행이 있다면, 그 행 지우고 점수 올리고 그 위 블록들을 잘 내림
- 연한 칸에 블록이 있으면 블록이 차지하는 행 만큼 밑으로 전부 밀기
턴이 전부 끝났으면 점수와 남은 타일의 수를 출력합니다
행 지우고 나서 블록들을 잘 내리는게 핵심입니다. 나머지는 그냥 내려도 되는데 2x1는 밑에 두칸을 보면서 내려줘야 합니다
내릴 때는 아래 있는 블록부터 밑으로 내려야 됩니다.
이러저러한 예외처리를 잘 해주시면 됩니다
코드는.... 너무 극혐이라 올릴까 말까 했는데... 여러분의 알 권리를 위해 올리겠습니다.
#pragma GCC optimize ("Ofast")
#define _CRT_SECURE_NO_WARNINGS
#define _SILENCE_CXX17_C_HEADER_DEPRECATION_WARNING
#include <bits/stdc++.h>
using namespace std;
int board_green[10][4];
int board_blue[10][4]; // 문제에 써있는거랑 인덱스 같음
int score;
// y, x에 있는 블록 밑으로 쭉 내리기
void pull_down(int y, int x, bool is_green) {
if (is_green) {
int target_y = y;
while (1) {
if ((target_y + 1 < 10 && board_green[target_y + 1][x] == 0)
&& (board_green[y][x]&1 || (x<3 && board_green[y][x]==2 && board_green[y][x+1]==2 && board_green[target_y+1][x+1]==0)))
++target_y;
else
break;
}
if (y == target_y) return;
if (board_green[y][x] == 2) {
swap(board_green[y][x + 1], board_green[target_y][x + 1]);
swap(board_green[y][x], board_green[target_y][x]);
}
else
swap(board_green[y][x], board_green[target_y][x]);
}
else {
int target_y = y;
while (1) {
if ((target_y + 1 < 10 && board_blue[target_y + 1][x] == 0)
&& (board_blue[y][x] & 1 || (x < 3 && board_blue[y][x] == 2 && board_blue[y][x + 1] == 2 && board_blue[target_y + 1][x + 1] == 0)))
++target_y;
else
break;
}
if (y == target_y) return;
if (board_blue[y][x] == 2) {
swap(board_blue[y][x + 1], board_blue[target_y][x + 1]);
swap(board_blue[y][x], board_blue[target_y][x]);
}
else
swap(board_blue[y][x], board_blue[target_y][x]);
}
}
// type: 1: 한칸, 2: 가로, 3: 세로
void put(int type, int y, int x) {
// green
board_green[y][x] = type;
if (type == 2) board_green[y][x + 1] = type;
else if (type == 3) board_green[y + 1][x] = type;
if (type == 3) pull_down(y + 1, x, true);
pull_down(y, x, true);
swap(y, x);
// blue
if (type == 2) type = 3;
else if (type == 3) type = 2;
board_blue[y][x] = type;
if (type == 2) board_blue[y][x + 1] = type;
else if (type == 3) board_blue[y + 1][x] = type;
if (type == 3) pull_down(y + 1, x, false);
pull_down(y, x, false);
}
// 연한 부분에 블록 있으면 밀기
void push() {
// 초록
int push_cnt = 0;
push_cnt += (board_green[4][0]+board_green[4][1]+board_green[4][2]+board_green[4][3] > 0) +
(board_green[5][0]+board_green[5][1]+board_green[5][2]+board_green[5][3] > 0);
if (push_cnt) {
for (int i = 9 - push_cnt; i >= 6 - push_cnt; --i) {
for (int j = 0; j < 4; ++j) {
board_green[i + push_cnt][j] = board_green[i][j];
}
}
for (int i = 4; i <= 5; ++i)
for (int j = 0; j < 4; ++j)
board_green[i][j] = 0;
}
// 파랑
push_cnt = 0;
push_cnt += (board_blue[4][0] + board_blue[4][1] + board_blue[4][2] + board_blue[4][3] > 0) +
(board_blue[5][0] + board_blue[5][1] + board_blue[5][2] + board_blue[5][3] > 0);
if (push_cnt) {
for (int i = 9 - push_cnt; i >= 6 - push_cnt; --i) {
for (int j = 0; j < 4; ++j) {
board_blue[i + push_cnt][j] = board_blue[i][j];
}
}
for (int i = 4; i <= 5; ++i)
for (int j = 0; j < 4; ++j)
board_blue[i][j] = 0;
}
}
// 가득찬 행 or 열 지움
bool erase() {
int erased_cnt = 0;
// 초록
for (int i = 9; i >= 6; --i) {
bool empty = false;
for (int j = 0; j < 4 && !empty; ++j)
if (board_green[i][j] == 0)
empty = true;
if (!empty) {
for (int j = 0; j < 4; ++j)
board_green[i][j] = 0;
++erased_cnt;
}
}
// 내리기
for (int i = 8; i >= 4; --i) {
for (int j = 0; j < 4; ++j) {
if (board_green[i][j] == 0) {
continue;
}
pull_down(i, j, true);
}
}
// 파랑
for (int i = 9; i >= 6; --i) {
bool empty = false;
for (int j = 0; j < 4 && !empty; ++j)
if (board_blue[i][j] == 0)
empty = true;
if (!empty) {
for (int j = 0; j < 4; ++j)
board_blue[i][j] = 0;
++erased_cnt;
}
}
// 내리기
for (int i = 8; i >= 4; --i) {
for (int j = 0; j < 4; ++j) {
if (board_blue[i][j] == 0) {
continue;
}
pull_down(i, j, false);
}
}
score += erased_cnt;
return erased_cnt;
}
void debug_print() {
// board 출력
cout << "------\n";
cout << "score: " << score << '\n';
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
if (i < 4 && j < 4) cout << '-' << ' ';
else if (i >= 4 && j >= 4) cout << '*' << ' ';
else if (j >= 4) cout << board_blue[j][i] << ' ';
else cout << board_green[i][j] << ' ';
}
cout << '\n';
}
cout << '\n';
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
//freopen("output.txt", "w", stdout);
#endif
ios_base::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int n;
cin >> n;
while (n--) {
int t, y, x;
cin >> t >> y >> x;
put(t, y, x);
// loop
while (erase())
;
push();
debug_print();
}
int cnt = 0;
for (int i = 6; i <= 9; ++i) {
for (int j = 0; j < 4; ++j) {
cnt += (board_green[i][j] != 0);
cnt += (board_blue[i][j] != 0);
}
}
cout << score << '\n' << cnt << '\n';
return 0;
}
제 코드는 그냥 무시하시고 풀어주십쇼
반응형
'Online Judge > 백준' 카테고리의 다른 글
[백준][C++] 1520: 내리막 길 (0) | 2020.07.14 |
---|---|
[백준][C++] 19230: Datum (0) | 2020.07.14 |
[백준][C++] 9663: N-Queen (0) | 2020.07.13 |
[백준][C++] 14888: 연산자 끼워넣기 (0) | 2020.07.12 |
[백준][C++] 17135: 캐슬 디펜스 (0) | 2020.07.12 |