2 minute read

코드

#include <bits/stdc++.h>
#define ll long long
using namespace std;
#define X first
#define Y second

// 방향성 배열
int dx[4] = { 1, 0, -1, 0 }; // 상하좌우 방향에 대한 x좌표 설정
int dy[4] = { 0, 1, 0, -1 }; // 상하좌우 방향에 대한 y좌표 설정

string board[1001]; // 건물 지도를 나타내는 문자열 배열
int fire[1001][1001]; // 불이 몇 초 후에 전파되는지 저장하는 배열
int sang[1001][1001]; // 상근이가 몇 초 만에 이동하는지 저장하는 배열

int main(void)
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    // 테스트 케이스 수 입력
    int t; cin >> t;
    while (t--)
    {
        int w, h; cin >> w >> h;

        // 불과 상근이의 위치를 저장할 큐 선언
        queue<pair<int, int>> st, f;

        // 빌딩 지도를 입력받고, 초기화 작업 수행
        for (int i = 0; i < h; i++)
        {
            cin >> board[i];
            fill(fire[i], fire[i] + w, -1);
            fill(sang[i], sang[i] + w, -1);
            for (int j = 0; j < w; j++)
            {
                if (board[i][j] == '@') // 상근이 위치를 큐에 삽입하고 상근 배열을 0으로 초기화
                {
                    sang[i][j] = 0;
                    st.push({ i,j });
                }

                if (board[i][j] == '*') // 불의 위치를 큐에 삽입하고 불 배열을 0으로 초기화
                {
                    fire[i][j] = 0;
                    f.push({ i,j });
                }
            }
        }

        // 불에 대한 확산 시뮬레이션(Breadth-First Search) 실행
        while (!f.empty())
        {
            auto cur = f.front(); f.pop();
            
            // 사방으로 확산하는 과정
            for (int dir = 0; dir < 4; dir++)
            {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];

                // 벽을 넘어가지 않는 경우 확인
                if (nx < 0 || ny < 0 || nx >= h || ny >= w) continue;
                // 이동할 위치가 빈 칸이고 불이 아직 전파되지 않은 경우
                if (board[nx][ny] != '.' || fire[nx][ny] >= 0) continue;

                // 불이 확산되는 시간 설정
                fire[nx][ny] = fire[cur.X][cur.Y] + 1;
                f.push({ nx,ny });
            }
        }

        bool ex = 0; // 탈출 여부 변수
        // 상근이가 벽을 향해 이동하는 시뮬레이션 실행
        while (!st.empty())
        {
            auto cur = st.front(); st.pop();
            for (int dir = 0; dir < 4; dir++)
            {
                int nx = cur.X + dx[dir];
                int ny = cur.Y + dy[dir];

                // 경계를 벗어난다면 탈출 시간 출력 후 break
                if (nx < 0 || ny < 0 || nx >= h || ny >= w)
                {
                    ex = 1;
                    cout << sang[cur.X][cur.Y] + 1 << "\n";
                    break;
                }

                // 이동할 위치가 빈 칸이고 상근이가 아직 이동하지 않은 경우
                if (board[nx][ny] != '.' || sang[nx][ny] >= 0) continue;
                // 이동할 위치의 불 전파 시간이 이동 시간보다 빠른 경우, 이동할 수 없음.
                if (fire[nx][ny] <= sang[cur.X][cur.Y] + 1 && fire[nx][ny] != -1) continue;

                // 상근이가 이동하는 시간 설정
                sang[nx][ny] = sang[cur.X][cur.Y] + 1;
                st.push({ nx,ny });
            }
            if (ex) break; // 출구를 찾았다면 루프 종료
        }

        if (ex != 1) // 탈출이 불가능 경우 "IMPOSSIBLE" 출력
            cout << "IMPOSSIBLE\n";
    }
    return 0;
}

불 bfs는 그냥 돌리면 되고 상근이의 이동에서 예외 처리가 중요한 문제였다.

 if (fire[nx][ny] <= sang[cur.X][cur.Y] + 1 && fire[nx][ny] != -1) continue;

여기서&& fire[nx][ny] != -1인 이유는 처음에 -1로 도착안했음을 초기화했기에 이 예외처리를 안하면 불의 이동시간이 상근이의 다음 이동시간보다 항상 작기때문.

Leave a comment