첫째 줄에 테스트 케이스의 개수가 주어진다. 테스트 케이스는 최대 100개이다.
각 테스트 케이스의 첫째 줄에는 빌딩 지도의 너비와 높이 w와 h가 주어진다. (1 ≤ w,h ≤ 1000)
다음 h개 줄에는 w개의 문자, 빌딩의 지도가 주어진다.
'.': 빈 공간
'#': 벽
'@': 상근이의 시작 위치
'*': 불
각 지도에 @의 개수는 하나이다.
각 테스트 케이스마다 빌딩을 탈출하는데 가장 빠른 시간을 출력한다. 빌딩을 탈출할 수 없는 경우에는 "IMPOSSIBLE"을 출력한다.
#include<iostream>
#include<queue>
using namespace std;
//#,@,.,*입력받는 배열
char building[1001][1001];
//상근이가 갈수있는 좌표 담는 큐(bfs에서)
queue<pair<int,int>> person;
//상근이가 움직인 좌표의 방문여부
int visitedP[1001][1001];
//불이 옮겨붙는 좌표 담는 큐(bfs에서 사용)
queue<pair<int,int>> fire;
//불이 옮겨붙는 좌표 방문 여부
int visitedF[1001][1001];
//상하좌우 좌표 반복문처리하기위한 배열
int dx[4] = {0,0,-1,1};
int dy[4] = {1,-1,0,0};
//열, 행
int width = 0, height = 0;
void solution();
/// <summary>
/// 방문 배열, 큐 초기화
/// </summary>
void init() {
fill(&visitedF[0][0], &visitedF[height][width], 0);
fill(&visitedP[0][0], &visitedP[height][width], 0);
while (!fire.empty()) {
fire.pop();
}
while (!person.empty()) {
person.pop();
}
}
/// <summary>
/// 입력값 받는 함수
/// </summary>
void input() {
int tc = 0;
cin >> tc;
for (int index = 0; index < tc; index++) {
cin >> width >> height;
init();
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
cin>>building[i][j];
//시작지점이면 상근 큐에 푸시
if (building[i][j] == '@') {
person.push({ i,j });
//방문 했다고 체크
visitedP[i][j] = 1;
}
//산불지점이면 불 큐에 푸시
else if (building[i][j] == '*') {
fire.push({i,j});
//방문 했다고 체크
visitedF[i][j] = 1;
}
}
}
solution();
}
}
void solution() {
//움직인 거리
int level = 1;
while (!person.empty()) {
//각 레벨에서 큐 사이즈만큼만 반복하기 위한 변수
int qSize = person.size();
int fSize = fire.size();
//불 먼저 레벨 1만큼 진행
for (int k = 0; k < fSize; k++) {
pair<int, int> tmp = fire.front();
fire.pop();
for (int i = 0; i < 4; i++) {
int nextA = tmp.first + dx[i];
int nextB = tmp.second + dy[i];
//다음 좌표가 범위 내에 있으면서, '.'이어야 이동 가능('*'이나 '@'는 신경안써도됨)
if (nextA >= 0 && nextB >= 0 && nextA < height && nextB < width && (building[nextA][nextB] == '.')) {
//방문안했다면
if (!visitedF[nextA][nextB]) {
//방문 체크
visitedF[nextA][nextB] = 1;
//큐에 해당 좌표 푸시
fire.push({ nextA,nextB });
}
}
}
}
//상근이 진행
for (int i = 0; i < qSize; i++) {
pair<int, int> tmp = person.front();
person.pop();
for (int i = 0; i < 4; i++) {
int nextA = tmp.first + dx[i];
int nextB = tmp.second + dy[i];
//탈출할수 있다면
if (nextA<0 || nextA==height|| nextB<0 ||nextB==width) {
cout << level<<'\n';
return;
}
//범위내에 있으면서, 다음 칸이 빈 공간이면서, 불길이 안닿은 곳이면
if (nextA >= 0 && nextB >= 0 && nextA < height && nextB < width && building[nextA][nextB] == '.' && visitedF[nextA][nextB] != 1) {
if (!visitedP[nextA][nextB]) {
visitedP[nextA][nextB] = 1;
person.push({ nextA,nextB });
}
}
}
}
level++;
}
//반복문 빠져나오면 탈출을 못한 것이므로
cout << "IMPOSSIBLE" << '\n';
}
int main() {
input();
}
탈출 조건을
if (building[nextA][nextB]=='.' && visitedF[nextA][nextB] != 1 && (nextA == 0 || nextA == height - 1 || nextB == 0 || nextB == width - 1)) {
//경계면에 도달햇으므로 탈출하려면 1만큼 더 증가시켜서 출력
cout << level+1<<'\n';
return;
}
다음 칸에 경계면에 도달했고, 빈칸이라면('.') 탈출했으므로
level을 1만큼 증가시켜서 출력하는 방식으로 구현을 하였다.
하지만, @.. 이런식으로 출발하자마자 바로 탈출 할 수 있는 경우에서
바로 탈출이 아니라 빈칸으로 향해서 오답이 나왔다.
따라서,
//탈출할수 있다면
if (nextA<0 || nextA==height|| nextB<0 ||nextB==width) {
cout << level<<'\n';
return;
}
범위밖으로 벗어났을 때, 출력하도록 변경하니 정답이 나왔다.