문제
8×8 체스판에서 벽이 매 턴 한 칸씩 아래로 내려온다. 왼쪽 아래(7,0)에서 오른쪽 위(0,7)로 이동할 수 있는지 판별하는 문제다.
핵심 아이디어
- 캐릭터는 상하좌우 + 대각선 + 제자리, 총 9방향으로 이동 가능하다.
- 캐릭터 이동 → 벽 이동 → 생존 체크 순서로 진행된다.
- 모든 벽이 사라지면 반드시 도달 가능하므로
return 1. - 8×8 고정 크기이므로 DFS로도 시간 내에 풀 수 있다.
풀이
#include <iostream>
#include <vector>
using namespace std;
struct Vector { int x, y; };
Vector directions[9] = {
{0,0}, {1,0}, {1,1}, {1,-1},
{-1,0}, {-1,1}, {-1,-1}, {0,1}, {0,-1}
};
bool is_remain_walls(vector<vector<char>>& field) {
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
if (field[7 - i][j] == '#') return true;
return false;
}
bool is_alive(vector<vector<char>>& field, Vector pos) {
return field[pos.y][pos.x] == '.';
}
void move_wall(vector<vector<char>>& field) {
for (int i = 0; i < 7; i++)
for (int j = 0; j < 8; j++)
field[7 - i][j] = field[7 - i - 1][j];
for (int i = 0; i < 8; i++)
field[0][i] = '.';
}
int solution(vector<vector<char>> field, Vector pos,
bool is_wall_move = true) {
if (is_wall_move) move_wall(field);
if (!is_alive(field, pos)) return 0;
if (!is_remain_walls(field)) return 1;
int ret = 0;
for (int i = 0; i < 9; i++) {
Vector next = {pos.x + directions[i].x,
pos.y + directions[i].y};
if (next.x < 0 || next.y < 0 ||
next.x >= 8 || next.y >= 8) continue;
if (field[next.y][next.x] == '#') continue;
if (!is_alive(field, next)) continue;
ret |= solution(field, next);
}
return ret;
}
int main() {
vector<vector<char>> field(8, vector<char>(8, ' '));
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
cin >> field[i][j];
cout << solution(field, {0, 7}, false) << endl;
return 0;
}
주요 포인트
field를 값 복사로 넘겨서 각 분기마다 독립적인 상태를 유지한다.ret |= solution(...)— 하나라도 성공하면 1을 반환한다.- 벽은 최대 8턴 후 모두 사라지므로 탐색 깊이가 제한적이다.
- 시작 위치
{0, 7}은 왼쪽 아래를 의미한다 (x=0, y=7).
복잡도
- 시간: O(9^8) — 최악의 경우, 실제로는 가지치기로 훨씬 적음
- 공간: O(8 × 8 × depth) — 재귀마다 field 복사
고정 크기 맵에서의 완전 탐색, 상태 복사와 벽 이동 순서를 정확히 구현하는 것이 관건이다.
댓글