문제 출처
1. 문제설명
NxM
행렬로 표현되는 맵이 주어진다.
0
은 이동할 수 있는 곳, 1
은 벽
(1, 1)
에서 (N, M)
까지 최단 경로를 구하라
- 만약 이동하는 도중에 한 개의 벽을 부수고 이동했을 때 경로가 더 짧아진다면,
- 벽을 한 개까지 부수고 이동해도 된다.
- 최단 경로 출력, 경로가 없다면
-1
2. 알고리즘 설계
BFS
문제로 최단 경로를 구한다.
- 벽을 부쉈을 때와 부수지 않았을 때를 같이 실행하면 된다.
3. 로직
- 첫번째 접근 방법 (시간초과)
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
cin >> map[i][j];
if (map[i][j] == '1')
wall.push_back({ i, j });
}
for (pii cur : wall) {
map[cur.first][cur.second] = '0';
ans = min(ans, bfs(cur));
map[cur.first][cur.second] = '1';
}
- 이동 중에 벽을 부수지 않는 경우와 벽을 한 개 부순 경우를 같이 큐에 담기
for(int dir=0; dir<4; dir++) {
int ny = cur.y + dy[dir];
int nx = cur.x + dx[dir];
if(map[ny][nx] == '1' && 벽 부수기 가능) // 벽 부수고 이동
if(map[ny][nx] == '0') // 그냥 이동할 수 있다면
}
4. 전체 코드
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int dy[] = { -1,1,0,0 };
const int dx[] = { 0,0,-1,1 };
const int sz = 1001;
int visited[sz][sz][2] = { 0, };
char map[sz][sz];
int n, m;
typedef struct { int y, x, crush; }pos;
int bfs(void)
{
queue<pos> q;
q.push({ 0,0,0 });
visited[0][0][0] = 1;
while (!q.empty()) {
pos cur = q.front();
q.pop();
if (cur.y == n - 1 && cur.x == m - 1)
return visited[cur.y][cur.x][cur.crush];
for (int dir = 0; dir < 4; dir++) {
int ny = cur.y + dy[dir];
int nx = cur.x + dx[dir];
if (ny < 0 || nx < 0 || ny >= n || nx >= m)
continue;
if (visited[ny][nx][cur.crush])
continue;
if (map[ny][nx] == '1' && !cur.crush) {
q.push({ ny, nx, 1 });
visited[ny][nx][1] = visited[cur.y][cur.x][cur.crush] + 1;
}
if (map[ny][nx] == '0') {
q.push({ ny, nx, cur.crush });
visited[ny][nx][cur.crush] = visited[cur.y][cur.x][cur.crush] + 1;
}
}
}
return -1;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> n >> m;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
cin >> map[i][j];
cout << bfs();
}
5. 소감
- 처음에 벽 하나씩 부수고 탐색하는 방향으로 구현하였다.
- 생각해보니 맵의 대부분이 벽이라면?
- 거의
size
의 제곱만큼 BFS
를 돌게 될 것이다.
- 3차원
visited
배열을 이용
- 한 번의 이동으로 모든 조건을 검사할 수 있었다.
BFS
문제 대부분 2차원 맵이 주어졌다. (내가 푼 문제)
- 3차원 배열을 떠올리기까지 조금 오래 걸렸다..
- 어떻게 하면 시간을 줄일 수 있을까 굉장히 고민했던 거 같다.
- 이 문제 외에도 BFS 문제를 더 풀었지만, 구현 방식이 거의 동일해 포스팅하지 않았다.
- BFS 관련 문제 유형
- 최단 경로
- 영역이 몇 개인지?
- 영역의 칸 수
- 무엇이 확산되는 조건 추가
- 탈출까지 걸리는 시간
- 최대 확산되기까지 걸리는 시간(1번이 1초)
- 문제 유형에서 상위 3개는 최단 경로 구하는 방식과 거의 다르지 않다.
- 확산 조건이 추가되면,
queue
의 size만큼 BFS
를 해주면 된다.