BFS는 그래프라는 자료구조에서 노드를 방문하기 위한 알고리즘이다.
우리의 목표는 (0,0)과 상하좌우로 이어진 모든 파란색 칸을 확인하는 것이다.
우선 BFS 알고리즘에서는 좌표를 담을 큐가 필요하다.
BFS 알고리즘이 시작되면 우선 (0,0)에 방문했다는 표시를 남기고 해당 칸을 큐에 넣는다.
이 초기 세팅이 끝난 후에는 큐가 빌 때까지 계속 큐의 front를 빼고 해당 좌표의 상하좌우를 살펴보면서 큐에 넣어주는 작업을 반복하게 된다.
지금 상황에서 큐의 front는 (0,0)이고 pop을 한다. 그리고 (0,0)의 상하좌우 칸을 보는데, 이 중에서 우리는 파란색 칸이면서 아직 방문하지 않은 칸을 찾는다.
.....
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
int board[502][502];
bool vis[502][502];
int n = 7, m = 10;
int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
queue<pair<int, int>> Q;
vis[0][0] = 1;
Q.push({0, 0});
while(!Q.empty()){
pair<int, int> cur = Q.front(); Q.pop();
for(int dir = 0 ; dir < 4; dir++){
int nx = cur.X + dx[dir];
int ny = cur.Y + dy[dir];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) continue;
if(vis[nx][ny] || board[nx][ny] != 1) continue;
vis[nx][ny] = 1;
Q.push({nx, ny});
}
}
}
BFS를 이용해 시작점에서 연결된 다른 모든 점으로의 최단 경로를 찾을 수 있다.
거리를 저장할 dist 배열을 두고 상하좌우의 칸을 볼 때 값을 잘 넣어주면 된다.
이 배열을 미리 -1로 초기화 해두면 굳이 vis배열을 따로 두지 않아도 방문 여부를 확인할 수 있다.
// Online C++ compiler to run C++ program online
#include <iostream>
#include <algorithm>
#include <string>
#include <queue>
#include <map>
#define fastio cin.tie(0), ios_base::sync_with_stdio(0)
using namespace std;
int n, m;
int board[102][102];
int dist[102][102];
const int dy[4] = {-1, 0, 1, 0};
const int dx[4] = {0, 1 ,0, -1};
int y, x;
int main() {
fastio;
cin >> n >> m;
string str;
for(int i = 0 ; i < n; i++){
cin >> str;
for(int j = 0; j < m; j++){
board[i][j] = str[j] - '0';
}
}
fill(&dist[0][0], &dist[0][0] + 102 * 102, -1);
dist[0][0] = 0;
queue<pair<int, int>> q;
q.push({0, 0});
while(!q.empty()){
tie(y, x) = q.front(); q.pop();
for(int i = 0 ; i < 4; i++){
int ny = y + dy[i];
int nx = x + dx[i];
if(ny < 0 || nx < 0 || ny >= n || nx >=m) continue;
if(board[ny][nx] == 0 || dist[ny][nx] > -1) continue;
dist[ny][nx] = dist[y][x] + 1;
q.push({ny, nx});
}
}
cout << dist[n-1][m-1] + 1<< '\n';
}
내 코드
시작점이 여러 개 일때 해당 위치를 시작점으로 하는 BFS를 한 번씩 다 돌릴 수 있지만, 그렇다면 시간복잡도가 너무 커진다.
해결법은 의외로 간단하다. 그냥 모든 시작점을 큐에 넣고 앞에서 한 것과 똑같이 BFS를 돌면 된다.
불의 전파를 BFS로 처리할 수 있는데, 탈출하는 사람도 처리를 해주어야 한다.
결론적으로, 불에 대한 탈출자에 대한 BFS를 모두 돌림으로서 해결이 가능하다.
먼저 사람을 신경쓰지 말고 불에 대한 BFS를 돌려 미리 각 칸에 불이 전파되는 시간을 다 구해둔다.
그리고 사람에 대한 BFS를 돌려 특정 칸을 x시간에 최초로 방문할 수 있는데 그 칸에는 x시간이나 그 이전에 불이 부튼다면 그 칸을 못간다.
창의성을 발휘해서, 이 문제에서도 수빈이가 X에 있다고 할 때 X-1, X+1, 2X로 이동하는 것을 BFS로 처리할 수 있다.