Algorithm

[백준(파이썬/Python)] 2638_치즈

kindof 2021. 8. 1. 16:24

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

 

2638번: 치즈

첫째 줄에는 모눈종이의 크기를 나타내는 두 개의 정수 N, M (5 ≤ N, M ≤ 100)이 주어진다. 그 다음 N개의 줄에는 모눈종이 위의 격자에 치즈가 있는 부분은 1로 표시되고, 치즈가 없는 부분은 0으로

www.acmicpc.net

 

이 문제의 핵심은 내부 치즈인가 아닌가를 어떤 방식으로 판단할 것인가입니다.

 

처음 문제에 접근했을 때는"모든 지점에 대하여 내부 치즈인가를 BFS 탐색을 하였고, 만약 가장자리에 도착할 수 있으면 내부 치즈가 아니다"라고 생각했습니다.

 

하지만 그렇게 되면 모든 위치마다 일일이 체크를 해줘야 하기 때문에, 시간복잡도에서 불리할 수밖에 없습니다.

 

이를 해결하기 위해서는 반대로 "가장 자리(0,0)에서 출발하여 도착할 수 있는 모든 지점은 내부 치즈가 아니다"라고 접근해야 합니다. 치즈를 지우기 전에 (0,)에서 DFS를 한 번만 수행해주면, 각 위치에 있는 치즈가 내부 치즈인지 아닌지를 한 번에 확인할 수 있습니다. 

 

그리고 치즈를 삭제할 때는 단순하게 상하좌우를 살펴서 외부 공기가 2개 이상이면 지워주는 방식으로 하면 됩니다.

 

[풀이]

import sys
from collections import deque


def checkOutsizeCheeze(i,j):
    visited = [[False] * m for _ in range(n)]
    visited[i][j] = True
    cheeze[i][j] = 2
    q = deque()
    q.append((i,j))

    while q:
        x, y = q.popleft()
        for d in range(4):
            nx, ny = x + dx[d], y + dy[d]
            if 0 <= nx < n and 0 <= ny < m and not visited[nx][ny] and cheeze[nx][ny] != 1:
                visited[nx][ny] = True
                cheeze[nx][ny] = 2
                q.append((nx,ny))
    return False

def deleteCheeze():
    n, m = len(cheeze), len(cheeze[0])
    visited = [[False] * m for _ in range(n)]
    delete_list = []

    for i in range(1, n-1):
        for j in range(1, m-1):
            visited[i][j] = True
            count = 0
            for k in range(4):
                ni, nj = i + dx[k], j + dy [k]
                if cheeze[ni][nj] == 2:
                    count += 1
                    if count == 2:
                        delete_list.append((i,j))
                        break

    for x, y in delete_list:
        cheeze[x][y] = 0

n, m = map(int, input().split())
cheeze = [list(map(int, sys.stdin.readline().split())) for _ in range(n)]
dx, dy = [1,-1,0,0], [0,0,1,-1]
time = 0
while True:
    # 맨 바깥쪽 공기에서 dfs로 연결된 모든 치즈는 외부 치즈다.
    checkOutsizeCheeze(0,0)

    # 치즈 삭제
    deleteCheeze()
    time += 1
    
    # 모든 치즈가 녹았는지 확인
    cheezeCount = 0
    for i in range(n):
        for j in range(m):
            if cheeze[i][j] == 1:
                cheezeCount+= 1
    if cheezeCount == 0:
        break


print(time)