BOJ 4179. 불!
문제 풀이 과정을 공유하고자 한다.
문제 출처
1. 문제설명
- char형 배열에 맵이 주어진다.
.
,#
,J
,F
는 각각 지나갈 수 있는 공간, 벽, 초기위치, 불이 난 공간- J는 입력에서 하나만 주어진다.
- 불은 1초마다 상,하,좌,우로 퍼지게 된다.
- 지훈이와 불은 벽을 통과할 수 없다.
- 가장 빠른 탈출 시간을 출력하고, 탈출이 불가능하면 IMPOSSIBLE 출력
2. 알고리즘 설계
- 지훈이의 위치를 큐에 넣고 BFS
- 단, BFS의 마지막 부분에 불을 확산시키기 위한 로직 필요
3. 로직
- 지훈이의 위치를 저장하고 큐에 넣어준다.
- 지훈이의 위치는
.
으로 변환
- 지훈이의 위치는
- 지훈이의 위치에서 상,하,좌,우 중 갈 수 있는 모든 칸을 큐에 넣는다.
- 여기서 중요한 건 지훈이가 이동 가능한 모든 위치를 한번에 갱신시켜야 한다.
size()
를 이용해 현재 저장된 모든 위치를 한번에 갱신
while (!q.empty()) { int q_sz = q.size(); while (q_sz--) {....} }
- 여기서 중요한 건 지훈이가 이동 가능한 모든 위치를 한번에 갱신시켜야 한다.
-
불을 확산시키는 것 또한
size()
를 이용해 4방향을 전부 확산시켜야 한다.void spread(void) { int sz = fire.size(); while (sz--) {...} }
4. 전체 코드
#include <iostream>
#include <queue>
#include <string>
using namespace std;
using pii = pair<int, int>;
typedef struct {
int y, x, w;
}pos;
const int dy[] = { -1,1,0,0 };
const int dx[] = { 0,0,-1,1 };
const int SZ = 1001;
char map[SZ][SZ];
bool visited[SZ][SZ];
int r, c;
queue<pii> fire;
pos src;
void spread(void)
{
int sz = fire.size();
while (sz--) {
pii cur = fire.front();
fire.pop();
for (int dir = 0; dir < 4; dir++) {
int ny = cur.first + dy[dir];
int nx = cur.second + dx[dir];
if (ny < 0 || nx < 0 || ny >= r || nx >= c)
continue;
if (map[ny][nx] == '.') {
fire.push({ ny, nx });
map[ny][nx] = 'F';
}
}
}
}
int escape(void)
{
queue<pos> q;
q.push(src);
visited[src.y][src.x] = true;
while (!q.empty()) {
int q_sz = q.size();
while (q_sz--) {
pos cur = q.front();
q.pop();
if (map[cur.y][cur.x] == 'F')
continue;
if (cur.y == r - 1 || cur.y == 0 || cur.x == c - 1 || cur.x == 0)
return cur.w + 1;
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 >= r || nx >= c)
continue;
if (visited[ny][nx] || map[ny][nx] != '.')
continue;
q.push({ ny, nx, cur.w + 1 });
visited[ny][nx] = true;
}
}
spread();
}
return -1;
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> r >> c;
for (int y = 0; y < r; y++) {
for (int x = 0; x < c; x++) {
cin >> map[y][x];
if (map[y][x] == 'J') {
src = { y,x,0 };
map[y][x] = '.';
}
if (map[y][x] == 'F')
fire.push({ y,x });
}
}
int res = escape();
if (res < 0) cout << "IMPOSSIBLE";
else cout << res;
return 0;
}
5. 소감
queue
의size()
를 통해, 현재 저장된 모든 위치의 상,하,좌,우를 고려하는 문제- 핵심은 동시에 갱신시키는 것