Boj 16933) 벽 부수고 이동하기 3
문제
설명
-
각 위치에 대한 방문체크만 하면 틀린다. 같은 위치라도 남은 폭탄의 갯수에 따라 다른 결과를 얻을 수 있기 때문이다. 그러므로 방문 시 폭탄의 여부를 체크해서 더 많은 폭탄을 가지고 있을 때만 같은 위치에 중복으로 갈 수 있게 한다. 예를들어
int visitTB[1000][1000]
이런식으로 구성할 수 있겠다. 방문 체크 시 남은 폭탄에 해당하는 차원을 추가해bool visitTB[1000][1000][11]
이런식으로 처리할 수도 있지만, 이 경우는 모든 경우를 계산하게 되어 느리다. -
낮에는 쉴 필요가 없다. 그러므로 낮 밤 모두 쉬는걸 넣지 말자.
-
방문체크용 배열을 따로 만들기에는 공간이 너무 아까웠다. 그래서
board[]
의 맨 앞비트만0
,1
여부를 사용하고, 나머지 비트는 방문 시 가진 폭탄의 최태갯수를 넣었다.
시간 복잡도
O(\(\mathrm{N}\mathrm{M}\mathrm{K}\))
코드
int w, h, k;
unsigned char board[1001 * 1001];
int dx[]{ -1, 1, 0, 0 }, dy[]{ 0, 0, 1, -1 };
struct E {
E(int pos, int nBomb) : pos(pos), nBomb(nBomb) {}
int pos;
int nBomb = 0;
};
int main()
{
fastio;
cin >> h >> w >> k;
for (int i = 0; i < w*h; i++)
{
char tmp;
cin >> tmp;
board[i] = tmp - '0';
}
int nMove = 0;
queue<E> q;
q.push(E(0, k));
while (!q.empty())
{
int size = q.size();
bool day = (++nMove % 2);
for (int i = 0; i < size; i++)
{
auto tmp = q.front(); q.pop();
if (tmp.pos == w * h - 1) {
cout << nMove;
return 0;
}
int cur_x = tmp.pos % w, cur_y = tmp.pos / w;
for (int j = 0; j < 4; j++)
{
int x = cur_x + dx[j], y = cur_y + dy[j], d = y * w + x;
if (x < 0 || y < 0 || x >= w || y >= h) continue;
// board => [leftBomb+1][isOne] 이므로 맨 앞비트를 제거 후 남은 폭탄 갯수 비교
// 이때 board 의 기본값이 -1 이 될 수 없으므로 nBomb 에 1을 더해 nBomb == 0 의 경우 걸러지는걸 막음
if ((board[d] >> 1) >= tmp.nBomb + 1) continue;
if (board[d] & 0b1) // 이 위치가 가 `1` 일 때
{
if (tmp.nBomb > 0 && day) // 폭탄이 있고 낮일 때만 간다.
{
q.push(E(d, tmp.nBomb - 1));
board[d] = (tmp.nBomb + 1 << 1) | 0b1;
}
}
else { // 이 위치가 `0` 일 때
q.push(E(d, tmp.nBomb));
board[d] = (tmp.nBomb + 1 << 1);
}
}
if (!day) q.push(E(tmp.pos, tmp.nBomb)); // 밤에만 쉬어도 충분하다.
}
}
cout << -1;
}
댓글남기기