problem solving/백준

[C++] 백준 2638번: 치즈

u1qns 2024. 5. 18. 01:00

🔗 문제

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

 

✏️ 풀이

 

오랜만에 문제 정리

 

 

[상태]

N x M 맵 (100 x 100)

  • 치즈 1
  • 공기 0

[동작]

치즈 녹이기

  • 조건 (1) 치즈와 상하좌우로 맞닿아있는 공기가 2개 이상일 경우에만 녹는다.
  • 조건 (2) 치즈로 둘러 쌓인 내부의 공기는 치즈를 녹일 수 없다 - 문제 그림 참고

간단하게 생각해낸 큰 틀은 아래와 같다.

while(totalCheese) // 모든 치즈가 녹을 때까지
{
    ++answer; // 걸린 시간
    melt() // 치즈를 녹여보자.
}

 

일단 "한 칸"씩 치즈가 녹으니 BFS가 적합한 알고리즘이라고 판단했다.

이제 세부조건 맞춰주기 전에 생각을 해보자.

맵의 상태가 2개이기 때문에 queue에 넣을 수 있는 것도 2개다.

 

 

(1) 치즈 기준으로 bfs를 돈다.

해당하는 치즈가 녹을 수 있는지 사방 탐색을 해야한다.

  • 한셀마다 사방탐색을 하면, 사방탐색하는 부분이 중복되기 때문에 비효율이다.
  • 만약 시간이 된다고 하더라도, 치즈와 맞닿은 공기가 내부에 있는 공기인지 확인하기 힘들다. -> 조건 (2) 충족 X

 

(2) 공기 기준으로 bfs를 돈다.

문제에서 아래 문장으로 공기 기준으로 bfs 돌리라고 힌트를 주고 있다.  이 문제가 골드 4라 그런지 친절하다. 👍

모눈종이의 맨 가장자리에는 치즈가 놓이지 않는 것으로 가정한다.

 

치즈가 녹으면 공기자리는 계속 생기므로, 공기를 넣는게 더 효율적이다.

가장 자리 아무거나 (0, 0) 먼저 큐에 넣어서 공기들을 다 visited 처리해주자.

자연스럽게 치즈로 둘러 쌓여 버린 공기는 치즈에 막혀서 만날 수 없다. -> 조건 (2) 충족 O

 

 

조건 (1)을 충족 시키기 위해서 counter[][]을 선언해주었다.

공기로 탐색을 하다가 치즈를 만나면 공기랑 만났다고 ++counter를 해준다.

그리고 제거 조건 counter == 2가 되면, 녹이고 다른 queue에 넣어준다.

 

치즈가 녹으면 그 자리는 다시 공기가 차지하게 되는 점을 이용해야 한다. 

치즈가 녹은 위치가 다음번에 탐색할 공기들의 위치로 다시 재지정을 해준다.

이렇게 하면 다시 가장자리부터 치즈까지 닿기 위한 queue를 돌지 않아도 된다.

while(totalCheese)
{
        ++answer;
        air = melt(air); // 녹은 치즈의 위치를 담은 queue 반환
}

 

💾  소스

https://www.acmicpc.net/source/78483482