취미가 좋다

2636. 치즈 본문

알고리즘 문제풀이/백준

2636. 치즈

benlee73 2021. 9. 8. 19:19

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

 

2636번: 치즈

아래 <그림 1>과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(<그림 1>에서 네모 칸에 X친 부분)에는 치즈가 놓

www.acmicpc.net

Solution

import sys
input = sys.stdin.readline
from collections import deque

def melt():
    num = 0
    while(ready):
        i, j = ready.pop()
        cheese[i][j] = 0
        num += 1
    return num

def chk():
    while(q):
        i, j = q.pop()
        
        if cheese[i][j] == 1:
            ready.append((i,j))
            continue
        
        for d in delta:
            dr, dc = i+d[0], j+d[1]
            if (0 <= dr < row) and (0 <= dc < col) and not visited[dr][dc]:
                q.append((dr, dc))
                visited[dr][dc] = True
    return melt()    

row, col = map(int, input().split())
cheese = []
for _ in range(row):
    cheese.append(list(map(int, input().split())))

delta = [[-1, 0], [1, 0], [0, -1], [0, 1]]
now, pre = 10000, 10000
q = deque()
ready = deque()
time = -1

while(now):
    visited = [[False]*col for _ in range(row)]
    q.append((0,0))
    pre = now
    now = chk()
    time += 1

print(time)
print(pre)
  • 입력을 받고 필요한 변수를 선언한다.
    • now : 방금 chk( ) 함수를 통해서 녹은 치즈의 개수. 이게 0이 되면 pre가 정답이다.
    • pre : 이전 now 값
    • q : 녹을 치즈인지 확인하는 좌표가 들어간다.
    • ready : 녹을 치즈를 찾았을 때, 나중에 반영하기 위해 그 좌표를 넣는다.
    • time : 몇 번 chk( )를 돌았는지 count
  • 녹은 치즈가 하나도 없을 때까지 while을 반복한다.
  • visited를 초기화한다.
  • q에 시작좌표를 넣고 now를 pre에 백업한다.
  • chk( ) 실행하여 몇 개의 치즈가 녹았는 지 저장한다.
    • 큐에서 좌표를 뽑고 1이면 치즈이므로 ready에 넣고 탐색은 멈춘다.
    • 치즈가 아니면 4방향으로 탐색한다.
    • 범위를 넘지 않고 방문하지 않았다면 큐에 넣고 visited에 표시한다.
    • 큐가 비어 있게 되면 모든 검사를 한 것이므로 mel( ) 를 수행
      • ready에서 좌표를 꺼내면서 실제 cheese가 녹은 곳을 적용한다.
      • 녹은 치즈의 개수를 반환한다.

Another

n, m = map(int, input().split())
board = [list(map(int, input().split())) for i in range(n)]

visit = [[False]*m for i in range(n)]
stack = [(0, 0)]
cnt = 0
meltnum = 0
while True:
    melt = []
    while stack:
        y, x = stack.pop()
        for i,j in [(1,0),(-1,0),(0,1),(0,-1)]:
            dy, dx = y+i, x+j
            if 0<=dy<n and 0<=dx<m and not visit[dy][dx]:
                if board[dy][dx]==0 :
                    stack.append((dy, dx))
                else :
                    melt.append((dy, dx))
                visit[dy][dx] = True
    if melt:
        meltnum = len(melt)
    else :
        break
    stack.extend(melt)
    cnt+=1
print(cnt)
print(meltnum)
  • 비슷하지만 조금 다르고 효율적이다.
  • 입력으로 받은 board를 바꾸지 않고 visit만을 이용한다.
  • 스택에 있는 것을 빼면서 그 좌표가 범위에 들어있고, 방문한 곳이 아닌지 확인한다.
    • 조건을 만족하고 이게 치즈가 아니라면 스택에 넣고, 치즈라면 melt에 넣는다.
    • 방문한 곳을 체크한다.
  • 스택이 비어있으면 나오게 되고 melt의 길이로 녹은 치즈의 개수를 센다.
  • 그리고 melt에 있는 것을 스택에 넣어서 다음 후보로 사용한다.
  • 어차피 이전에 방문한 곳은 보지 않아도 되고, 치즈의 위치라도 방문한 곳은 안가므로 board를 수정할 필요가 없다.
  • 그렇게 melt가 비어있을 땐 더이상 녹을 치즈가 없다는 것이므로 마무리한다.

'알고리즘 문제풀이 > 백준' 카테고리의 다른 글

22868. 산책 (small)  (0) 2021.09.04
14890. 경사로  (0) 2021.08.26
1018. 체스판 다시 칠하기  (0) 2021.08.14
7568. 덩치  (0) 2021.08.13
2231. 분해합  (0) 2021.08.13
Comments