문제 출처
1. 문제설명
N*M
의 행렬로 표현되는 맵이 있다.
0
은 이동할 수 있는 곳, 1
은 이동할 수 없는 벽이 있는 곳을 나타낸다.
(1,1)
에서 (N,M)
까지 이동하려고 한다.
- 이동하지 않고 같은 칸에 머무르는 게 가능하다.
- 낮과 밤이 번갈아가면서 등장한다.
- 처음 이동할 때는 낮이고, 한번 이동할 때마다 낮과 밤이 바뀐다.
- 이동하지 않고 머무르는 경우에도 낮과 밤이 바뀌게 된다.
- 만약 이동하는 중에 벽을 부수고 이동하는 것이 좀 더 경로가 짧아진다면,
K
개까지 부수고 이동해도 된다.
2. 알고리즘 설계
- 일반적인 BFS 문제 유형에서 낮과 밤이라는 조건이 추가된 문제이다.
N*M
크기의 맵에서 K
(1<=K<=10)개의 벽을 부술 수 있는데, 낮과 밤이 추가되었다.
- 이동할 수 있는 곳을 탐색해주면서, 벽을 부쉈을 때, 낮일 때, 밤일 때를 각각 체크해주면 된다!
3. 전체 코드
#include <bits/stdc++.h>
using namespace std;
const int dy[] = {-1, 1, 0, 0};
const int dx[] = {0, 0, -1, 1};
const int SZ = 1000;
int n, m, k;
char board[SZ][SZ];
bool visited[SZ][SZ][11][2];
typedef struct
{
int y, x, w, k, state;
} Pos;
int bfs()
{
queue<Pos> q;
q.push({0, 0, 1, 0, 1});
visited[0][0][0][1] = true; // 낮을 1으로
while (!q.empty())
{
Pos cur = q.front();
q.pop();
if (cur.y == n - 1 && cur.x == m - 1)
return cur.w;
for (int dir = 0; dir < 4; dir++)
{
int ny = cur.y + dy[dir];
int nx = cur.x + dx[dir];
int nw = cur.w + 1;
int n_state = !cur.state;
if (ny < 0 || nx < 0 || ny >= n || nx >= m)
continue;
if (!visited[ny][nx][cur.k][n_state] && board[ny][nx] == '0')
{
q.push({ny, nx, nw, cur.k, n_state});
visited[ny][nx][cur.k][n_state] = true;
}
if (board[ny][nx] == '1' && cur.state && cur.k < k)
{
if (!visited[ny][nx][cur.k + 1][n_state])
{
q.push({ny, nx, nw, cur.k + 1, n_state});
visited[ny][nx][cur.k + 1][n_state] = true;
}
}
}
if (!visited[cur.y][cur.x][cur.k][!cur.state])
{
q.push({cur.y, cur.x, cur.w + 1, cur.k, !cur.state});
visited[cur.y][cur.x][cur.k][!cur.state] = true;
}
}
return -1;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> board[i][j];
cout << bfs();
return 0;
}
4. 소감