-
백준 - 모노미노도미노 2 (20061) [C++]문제 풀이/백준 2023. 9. 17. 23:52반응형
이 문제는 시뮬레이션 문제이다. 입력 N이 최대 10,000 이므로 각 루프마다 10,000번 이하의 연산 수를 가지면 1초 안에 풀 수 있다. 이 문제를 풀 때 중요한 포인트는 블록을 처음에 파란 부분과 초록 부분으로 옮길 때 어떻게 옮기는 지와 블록 한 줄이 사라졌을 때 어떻게 끝으로 밀지이다.
첫 번째 포인트에서는 move 함수를 정의하여 한 점에 대해 위치할 수 있는 좌표를 리턴한다. 이를 통해 2 x 1에서 파란 부분일 때나 1 x 2에서 초록 부분일 때를 해결할 수 있다. 두 경우 한 점씩 리턴받은 값을 비교하여 좀 더 빨간 부분에 가까운 쪽으로 좌표를 정하도록 하면 무리없이 구할 수 있다.
두 번째 포인트에서는 살짝 어려웠는데, 처음에 blue, green 전역 배열을 vector가 아닌 2차원 배열로 설정했었는데, 이러한 방식으로 구현하려면 상당히 복잡해진다. 배열 돌리기 문제처럼, 임시 벡터를 만들어 결과값을 저장하고, 이 임시 벡터를 전역 벡터와 스왑하면 간단하게 구현할 수 있다는 사실을 이용했다.
이 문제에서 주의할 점은 blue와 green의 좌표가 구현할 수록 헷갈리게 된다는 사실이다. 이 점만 조심하면 생각보다 어렵지 않게 풀 순 있다. 관건은 이 구현을 얼마나 빠르게 할 수 있느냐인 것 같았다.
#include <iostream> #include <utility> #include <algorithm> #include <vector> using namespace std; /* x가 행, y가 열 블록은 1x1, 1x2, 2x1 세가지 블록 놓을 위치를 빨간색 보드에서 선택하면, 파란색과 초록색으로 쭉 이동(경계 만나거나 다른 블록 만날때까지) 초록색 보드에서 행이 타일로 가득 차있다면 그 행의 타일은 모두 사라짐 사라진 이후에는 초록 보드에서 사라진 행 위의 블록이 사라진 행 수 만큼 아래로 이동 파란 보드의 경우는 열이 타일로 가득 차있다면 그 열의 타일이 모두 사라짐 사라진 이후 사라진 열수만큼 오른쪽 이동 한 행이나 열이 타일로 가득차 사라지면 1점 획득 연한 색으로 되어있는 경우는 맨 오른쪽/맨 아래쪽 행/열이 사라짐 만약 행/열이 가득찬 경우와 연한칸에 블록이 있는 경우 동시 발생 -> 행/열 가득찬거 없애는게 먼저, 모두 수행된 뒤 연한 칸 처리 블록은 보드에 놓인 이후에 다른 블록과 합쳐지지 않음 결과 : 얻은 점수, 초록색 보드와 파란색 보드에 타일이 있는 칸의 개수 t = 2 : 1 x 2 블록을 y, x / y, x + 1에 놓기 t = 3 : 2 x 1 블록을 y, x / y + 1, x에 놓기 블록 차지 칸이 빨간색 칸의 경계를 넘어가는 경우는 없음 ---- 알고리즘 구상 --- move의 경우 1x1은 문제없음 1x2의 경우 blue의 경우 y, x + 1 을 먼저 보냄 - 그 위에 연쇄적으로 쌓으면 됨 green의 경우 y,x 와 y,x+1을 보내봄 -> 둘중 레드에 가까운 쪽 기준으로 행/열 맞춤 2x1의 경우 반대로 move 함수의 경우 좌표 리턴 -> 한 점이 최종적으로 가능한 위치 리턴 - 내부에서 배열을 수정하지 않는 방식 1. move 2. delete (blue, green), moveRight, moveDown 3. delete (light blue, light green), moveRight, moveDown moveRight, moveDown이 제일 중요함 - 가장 바깥쪽으로 밀어주는 함수 */ #define BLUE 0 #define GREEN 1 vector<vector<bool>> blue(4, vector<bool>(6, false)); vector<vector<bool>> green(6, vector<bool>(4, false)); pair<int, int> move(int index, int color) { int y = 0, x = 0; switch (color) { case BLUE: // 오른쪽 이동, index는 행의 위치 while (x < 6) { if (blue[index][x]) { break; } x++; } x--; y = index; break; case GREEN: // 아랫쪽 이동 while (y < 6) { if (green[y][index]) { break; } y++; } y--; x = index; } return { y, x }; } void moveRight() { vector<vector<bool>> temp(4, vector<bool>(6, false)); int index = 5; for (int x = 5; x >= 0; x--) { // check bool flag = true; for (int y = 0; y < 4; y++) { if (blue[y][x]) { flag = false; break; } } if (!flag) { for (int y = 0; y < 4; y++) { temp[y][index] = blue[y][x]; } index--; } } blue = temp; } void moveDown() { vector<vector<bool>> temp(6, vector<bool>(4, false)); int index = 5; for (int y = 5; y >= 0; y--) { // check bool flag = true; for (int x = 0; x < 4; x++) { if (green[y][x]) { flag = false; break; } } if (!flag) { for (int x = 0; x < 4; x++) { temp[index][x] = green[y][x]; } index--; } } green = temp; } int deleteBlue() { int result = 0; for (int x = 2; x < 6; x++) { bool flag = true; for (int y = 0; y < 4; y++) { if (!blue[y][x]) { flag = false; break; } } if (flag) { result++; for (int y = 0; y < 4; y++) { blue[y][x] = false; } } } moveRight(); return result; } int deleteGreen() { int result = 0; for (int y = 2; y < 6; y++) { bool flag = true; for (int x = 0; x < 4; x++) { if (!green[y][x]) { flag = false; break; } } if (flag) { result++; for (int x = 0; x < 4; x++) { green[y][x] = false; } } } moveDown(); return result; } void deleteLightBlue() { int cnt = 0; for (int x = 0; x < 2; x++) { bool flag = true; for (int y = 0; y < 4; y++) { if (blue[y][x]) { flag = false; break; } } if (!flag) { cnt++; } } if (cnt == 2) { for (int x = 4; x < 6; x++) { for (int y = 0; y < 4; y++) { blue[y][x] = false; } } } else if (cnt == 1) { for (int y = 0; y < 4; y++) { blue[y][5] = false; } } moveRight(); } void deleteLightGreen() { int cnt = 0; for (int y = 0; y < 2; y++) { bool flag = true; for (int x = 0; x < 4; x++) { if (green[y][x]) { flag = false; break; } } if (!flag) { cnt++; } } if (cnt == 2) { for (int y = 4; y < 6; y++) { for (int x = 0; x < 4; x++) { green[y][x] = false; } } } else if (cnt == 1) { for (int x = 0; x < 4; x++) { green[5][x] = false; } } moveDown(); } void printBlue() { for (int y = 0; y < 4; y++) { for (int x = 0; x < 6; x++) { cout << blue[y][x] << " "; } cout << '\n'; } cout << '\n'; } void printGreen() { for (int y = 0; y < 6; y++) { for (int x = 0; x < 4; x++) { cout << green[y][x] << " "; } cout << '\n'; } cout << '\n'; } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); int N; cin >> N; int score = 0; int cnt = 0; for (int line = 0; line < N; line++) { int t, y, x; cin >> t >> y >> x; if (t == 1) { // 1 x 1 // 1-1. move to blue pair<int, int> nextBlue = move(y, BLUE); blue[nextBlue.first][nextBlue.second] = true; // 1-2. move to green pair<int, int> nextGreen = move(x, GREEN); green[nextGreen.first][nextGreen.second] = true; } else if (t == 2) { // 1 x 2 // 1-1. move to blue pair<int, int> nextBlue = move(y, BLUE); blue[nextBlue.first][nextBlue.second] = true; nextBlue = move(y, BLUE); blue[nextBlue.first][nextBlue.second] = true; // 1-2. move to green pair<int, int> green1 = move(x, GREEN); pair<int, int> green2 = move(x + 1, GREEN); int minY = min(green1.first, green2.first); green[minY][x] = true; green[minY][x + 1] = true; } else { // 2 x 1 // 1-1. move to blue pair<int, int> blue1 = move(y, BLUE); pair<int, int> blue2 = move(y + 1, BLUE); int minX = min(blue1.second, blue2.second); blue[y][minX] = true; blue[y + 1][minX] = true; // 1-2. move to green pair<int, int> nextGreen = move(x, GREEN); green[nextGreen.first][nextGreen.second] = true; nextGreen = move(x, GREEN); green[nextGreen.first][nextGreen.second] = true; } // 2. deleteBlue and deleteGreen score += deleteBlue(); score += deleteGreen(); deleteLightBlue(); deleteLightGreen(); } // blue for (int y = 0; y < 4; y++) { for (int x = 0; x < 6; x++) { if (blue[y][x]) { cnt++; } } } // green for (int y = 0; y < 6; y++) { for (int x = 0; x < 4; x++) { if (green[y][x]) { cnt++; } } } cout << score << '\n'; cout << cnt << '\n'; return 0; }
반응형'문제 풀이 > 백준' 카테고리의 다른 글
백준 - 스타트 택시 (19238) [C++] (0) 2023.09.24 백준 - 어른 상어 (19237) [C++] (0) 2023.09.18 백준 - 신입 사원 (1946) [C++] (0) 2023.08.17 백준 - 30 (10610) [C++] (0) 2023.08.16 백준 - 주유소 (13305) [C++] (0) 2023.08.16