problem solving/백준

[C++] 백준 5427번: 불

u1qns 2022. 8. 26. 17:14

🔗문제

https://www.acmicpc.net/problem/5427

 

5427번: 불

상근이는 빈 공간과 벽으로 이루어진 건물에 갇혀있다. 건물의 일부에는 불이 났고, 상근이는 출구를 향해 뛰고 있다. 매 초마다, 불은 동서남북 방향으로 인접한 빈 공간으로 퍼져나간다. 벽에

www.acmicpc.net

 

🖍풀이

 

불 좌표, 상근이 좌표를 저장할 두 개의 queue를 생성하고 입력 받을 때 push해준다.

std::queue<std::pair<int, int>> fire;
std::queue<std::pair<int, int>> me;

 

재방문 방지 배열도 만들어 주었다.

int visited[MAX][MAX];

가장 중요한 BFS 탐색 방법

 

불 이동이랑 상근이 이동의 탐색에 겹치는 코드가 많아서 함수로 해결했다.

void BFS(std::queue<std::pair<int, int>>& q, const bool isFire, bool& flag)

 

🔥 불 이동

if(isFire)
{
    if(!isValid(x, y))
        continue;
    
    //불은 상근이가 갔던 경로도 태우므로 재방문 검사가 필요없다.
    if(map[x][y] == '.')
    {
        q.push({x, y});
        map[x][y] = '*'; // 불태운 곳 표시
    }
}
  • 불의 이동에서 범위에 넘어가서는 안된다. 벽에는 불이 붙지 않는 이유도 있다.
  • 불은 재방문 검사를 하지 않는다. 상근이가 지나갔던 곳도 걍 태워버리기 때문이다.
  • 단, 아직 불이 붙지 않은 곳으로만 이동하고 map에도 화재 표시를 해준다. 상근이가 못 오는 구역이라는 걸 확실히 하기 위함이다.

 

👩🏻‍🚒 상근이 이동

if(!isValid(x, y))
{
    std::cout << visited[nowX][nowY];
    flag = true;
    return;
}

if(!visited[x][y] && map[x][y] == '.')
{
    q.push({x, y});
    visited[x][y] = visited[nowX][nowY] + 1;
}
  • 상근이가 유효 범위를 넘어갔다는 것은 탈출을 의미한다.
    • 참조로 데려온 flag를 true로 변경하고 탐색을 멈춘다.
  • 불이나 상근이가 방문하지 않은 빈공간이 있을 때 상근이가 갈 수 있는 경로를 추가해주고 지금까지 몇번 이동 했는지 표시 해준다.

 

출력

bool flag = 0;
while(!flag && !me.empty())
{
    BFS(fire, true, flag);
    BFS(me, false, flag);
}
std::cout << (flag ? "\n" : "IMPOSSIBLE\n");

불이 더 이상 이동할 좌표가 없다는 건 상관없지만!

상근이가 탈출도 못 했는데 더 이상 갈 곳이 없다면  탈출 실패를 뜻한다!!

 

 

 


도움이 된 반례

25%에서 틀렸습니다.를 보아서 백준의 질문 검색에 있는 게시글의 반례 도움을 받았다.

원인은 문제를 제대로 읽지 않아서다.

이제 불이 붙으려는 칸으로 이동할 수 없다.

 

상근이의 이동보다 불의 이동을 우선시 해야 한다.

1
3 3
###
#@.
##*
//정답: IMPOSSIBLE
//오답: 2

(들어가자 마자 25% 반례글이 있었다. 나같은 사람 많구나🥹)

 

 

 

💾 소스

#include <iostream>
#include <queue>
#include <memory.h>
#define MAX 1000

int R, C;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, -1, 1};
char map[MAX][MAX];
int visited[MAX][MAX];

bool isValid(int a, int b)
{
    if(a>=R || b>=C || a<0 || b<0)
        return false;
    return true;
}

void BFS(std::queue<std::pair<int, int>>& q, const bool isFire, bool& flag)
{
    int qSize = q.size();
    while(qSize--)
    {
        int nowX = q.front().first;
        int nowY = q.front().second;
        q.pop();
        
        for(int i=0; i<4; ++i)
        {
            int x = nowX + dx[i];
            int y = nowY + dy[i];
            
            if(isFire)
            {
                if(!isValid(x, y))
                    continue;
                
                if(map[x][y] == '.')
                {
                    q.push({x, y});
                    map[x][y] = '*';
                }
            }
            else // 상근이 이동
            {
                if(!isValid(x, y))
                {
                    std::cout << visited[nowX][nowY];
                    flag = true;
                    return;
                }
                
                if(!visited[x][y] && map[x][y] == '.')
                {
                    q.push({x, y});
                    visited[x][y] = visited[nowX][nowY] + 1;
                }
            }
        }
    }
    
    return;
}


int main()
{
    int T=0;
    std::cin >> T;
    while(T--)
    {
        std::queue<std::pair<int, int>> fire;
        std::queue<std::pair<int, int>> me;
        memset(visited, 0, sizeof(visited));
        memset(map, NULL, sizeof(map));
        
        std::cin >> C >> R;
        for(int i=0; i<R; ++i)
        {
            for(int j=0; j<C; ++j)
            {
                std::cin >>map[i][j];
                if(map[i][j] == '*')
                    fire.push({i, j});
                else if(map[i][j] == '@')
                {
                    me.push({i, j});
                    visited[i][j] = true;
                }
            }
        }
        
        bool flag = 0;
        while(!flag && !me.empty())
        {
            BFS(fire, true, flag);
            BFS(me, false, flag);
        }
        
        std::cout << (flag ? "\n" : "IMPOSSIBLE\n");

    } //T
    return 0;
}