문제 설명
- 가로 M, 세로 N, 높이 H의 토마토 상자
- 보관 후 하루가 지나면 익은 토마토의 위, 아래, 왼쪽, 오른쪽, 앞 뒤 여섯 방향의 토마토는 익는다
- 보관된 토마토들이 모두 익는데 소요되는 최소 일수
입력값
1. M, N, H ( 2 ≤ M ≤ 100, 2 ≤ N ≤ 100, 1 ≤ H ≤ 100 )
2. N개의 줄까지 하ㅏ의 상자에 담긴 토마토의 정보
- 1은 익은 토마토 0은 안익은 토마토 -1은 빈 공간
- 토마토가 하나 이상 익은 경우만 입력으로 주어진다
출력값
- 토마토가 모두 익는데 걸리는 최소 일수
- 저장될 때부터 모두 익어있으면 0 출력
- 토마토가 모두 익지 못하는 상황이면 -1
종합 결과
첫번째 시도
import copy
def mature(h,r,c) :
global time, time_tomato, tomato, H
check = 0 # 고립 확인
# 상우하좌
dr,dc = [-1,0,1,0],[0,1,0,-1]
for k in range(4) :
if 0 <= r+dr[k] < R and 0<= c+dc[k] < C :
if tomato[h][r+dr[k]][c+dc[k]] == -1 :
check += 1
elif tomato[h][r+dr[k]][c+dc[k]] == 0: # 익히지 않은 토마토
time_tomato[h][r+dr[k]][c+dc[k]] = 1
# 아래층
if 0 <= h-1 :
if tomato[h-1][r][c] == -1 :
check += 1
elif tomato[h - 1][r][c] == 0:
time_tomato[h-1][r][c] = 1
# 위층
if h+1 < H :
if tomato[h+1][r][c] == -1 :
check += 1
elif tomato[h + 1][r][c] == 0:
time_tomato[h+1][r][c] = 1
if check == 6 :
time = -1 # 고립된 값이 있는 상태
C,R,H = map(int,input().split())
time = 0
tomato = [[] for _ in range(H)]
for i in range(H) :
tomato[i] = [list(map(int,input().split())) for _ in range(R)]
time_tomato = copy.deepcopy()
while True :
need = C*R*H # need_mature
for f in range(H) : # floor
for i in range(R) :
for j in range(C) :
if tomato[f][i][j] == 1 :
need -= 1
mature(f,i,j)
if time == -1 :
break
elif tomato[f][i][j] == -1 :
need -= 1
if need == 0 :
break
tomato = time_tomato.copy()
time += 1
print(time)
- 처음엔 간단한 문제라고 생각하고 시작해서 하드코딩이 되어버림
- 0 이상의 값이 나오는 경우 올바르게 처리되지만,
- 토마토가 고립된 경우(-1 값)을 처리하는게 어려움
- 또한 시간초과로 답도 안나옴
두번째 시도 : BFS
from collections import deque
def bfs() :
q = deque()
# 방향 저장(h,r,c) 위아래 상하좌우
direction = [(-1,0,0),(1,0,0),(0,-1,0),(0,1,0),(0,0,-1),(0,0,1)]
# 익은 토마토 찾기
for h in range(H) :
for r in range(R) :
for c in range(C) :
if tomato[h][r][c] == 1 :
q.append((h,r,c,0)) # 0 : 시간
# 토마토 숙성시키기
while q :
h, r, c, time = q.popleft()
for dh,dr,dc in direction :
nh,nr,nc = h+dh, r+dr, c+dc
if 0<= nh < H and 0<= nr < R and 0<= nc < C and tomato[nh][nr][nc] == 0 :
tomato[nh][nr][nc] = 1
q.append((nh,nr,nc,time+1))
# 탐색 끝나면 숙성안된 토마토가 남았는지 확인
for h in range(H) :
for r in range(R) :
for c in range(C) :
if tomato[h][r][c] == 0 : # 고립된 토마토가 있다는 뜻
return -1
return time
# 입력 처리
C, R, H = map(int, input().split()) # 열, 행, 층 개수 입력
# 3차원 배열로 토마토 상태 입력 받음
tomato = [ [list(map(int, input().split())) for _ in range(R)] for _ in range(H) ]
# BFS를 수행하여 결과 출력
print(bfs())
-
224392KB, 672ms(PyPy3) 으로 성공
from collections import deque
def bfs():
global time
# 6방향(위, 아래, 왼쪽, 오른쪽, 앞, 뒤)을 표현하는 방향 벡터
directions = [
(-1, 0, 0), # 아래층
(1, 0, 0), # 위층
(0, -1, 0), # 왼쪽
(0, 1, 0), # 오른쪽
(0, 0, -1), # 앞쪽
(0, 0, 1) # 뒤쪽
]
# BFS 탐색에 사용할 큐를 생성
queue = deque()
# 초기 상태에서 익은 토마토(1)의 위치를 큐에 추가
for h in range(H): # 층 반복
for r in range(R): # 행 반복
for c in range(C): # 열 반복
if tomato[h][r][c] == 1:
# 큐에 (층, 행, 열, 현재 시간) 추가
queue.append((h, r, c, 0))
# BFS 탐색 시작
while queue:
h, r, c, time = queue.popleft() # 큐에서 가장 앞의 위치 정보 꺼냄
# 6방향 탐색
for dh, dr, dc in directions:
nh, nr, nc = h + dh, r + dr, c + dc # 새 좌표 계산
# 유효 범위 내에 있고, 익지 않은 토마토(0)일 경우
if 0 <= nh < H and 0 <= nr < R and 0 <= nc < C and tomato[nh][nr][nc] == 0:
tomato[nh][nr][nc] = 1 # 익은 상태로 갱신
queue.append((nh, nr, nc, time + 1)) # 큐에 새 위치와 시간 추가
# 탐색 종료 후, 익지 않은 토마토가 있는지 확인
for h in range(H):
for r in range(R):
for c in range(C):
if tomato[h][r][c] == 0: # 익지 않은 토마토가 있다면
return -1 # 고립 상태이므로 -1 반환
return time # 마지막으로 업데이트된 시간 반환
# 입력 처리
C, R, H = map(int, input().split()) # 열, 행, 층 개수 입력
# 3차원 배열로 토마토 상태 입력 받음
tomato = [ [list(map(int, input().split())) for _ in range(R)] for _ in range(H) ]
# BFS를 수행하여 결과 출력
print(bfs())
- 이해가 안되면 위의 자세한 주석 코드를 참고하면 된다
-
sys.stdin.readline 을 해서 시간을 줄여보려했으나,
-
결과는 223848KB, 684ms(PyPy3)로 유의미한 차이가 없었다
다른사람 풀이 공부 : 2차원 리스트
# 2차원 리스트로 만들어 풀이하는 방법
from collections import deque
import sys
input=sys.stdin.readline
# 입력 받기
M, N, H = map(int, input().split()) # M: 가로 칸 수, N: 세로 칸 수, H: 상자의 높이
boxes = [list(map(int, input().split())) for _ in range(N * H)] # 전체 토마토 상자 정보 (2차원 리스트로 연결)
all_row = N * H # 총 행의 개수 (세로 방향 + 층 개수 포함)
dx = [1, -1, 0, 0, N, -N] # 이동 방향: 오른쪽, 왼쪽, 아래, 위, 윗층, 아랫층
dy = [0, 0, 1, -1, 0, 0] # 이동 방향: x방향은 그대로, y방향은 오른쪽/왼쪽만
ripen_tomatos = deque() # 익은 토마토의 위치를 저장하는 큐
unripe = 0 # 익지 않은 토마토의 개수
# 초기 상태 확인
for i in range(all_row): # 전체 행 탐색
for j in range(M): # 각 행의 열 탐색
if boxes[i][j] == 1: # 익은 토마토인 경우
ripen_tomatos.append((i, j)) # 큐에 위치 추가
if boxes[i][j] == 0: # 익지 않은 토마토인 경우
unripe += 1 # 익지 않은 토마토 개수 증가
# 익지 않은 토마토가 없다면
if unripe == 0:
print(0) # 이미 모두 익어있으므로 0일 출력
else:
day = -1 # 날짜 초기화 (첫날 0일을 만들기 위해 -1로 시작)
# BFS로 토마토 익히기
while ripen_tomatos: # 익은 토마토가 있는 동안 반복
day += 1 # 날짜 증가
for _ in range(len(ripen_tomatos)): # 현재 익은 토마토들만 처리
x, y = ripen_tomatos.popleft() # 익은 토마토의 위치 꺼내기
for i in range(6): # 6방향 탐색
# 2차원 리스트에서 위아래로 넘어가는 경우 방지 (N으로 나눈 나머지를 이용)
if (i == 0 and x % N == N - 1) or (i == 1 and x % N == 0):
continue # 오른쪽에서 다음 행으로 넘어가는 경우, 왼쪽에서 이전 행으로 넘어가는 경우 스킵
nx, ny = dx[i] + x, dy[i] + y # 다음 위치 계산
# 범위 내에 있으면서 익지 않은 토마토라면
if 0 <= nx < all_row and 0 <= ny < M and boxes[nx][ny] == 0:
boxes[nx][ny] = 1 # 토마토를 익힘
ripen_tomatos.append((nx, ny)) # 새로운 익은 토마토 위치 추가
unripe -= 1 # 익지 않은 토마토 개수 감소
# 모든 토마토가 익었는지 확인
print(day if unripe == 0 else -1) # 모두 익었으면 걸린 날짜, 그렇지 않으면 -1 출력
- 2차원 리스트로 풀이하신 분이 있어서 코드 분석을 해보았다
-
143232KB, 420ms(PyPy3) 로 시간과 메모리 면에서 압도적이다
코드 업그레이드 시도
# 223348KB, 692ms(PyPy3)
# unripen 추가하여 속도 향상 기대!
# 했지만 더 느려짐
import sys
from collections import deque
input = sys.stdin.readline
def bfs() :
q = deque()
# 방향 저장(h,r,c) 위아래 상하좌우
direction = [(-1,0,0),(1,0,0),(0,-1,0),(0,1,0),(0,0,-1),(0,0,1)]
unripe = 0
# 익은 토마토 찾기
for h in range(H) :
for r in range(R) :
for c in range(C) :
if tomato[h][r][c] == 1 :
q.append((h,r,c,0)) # 0 : 시간
elif tomato[h][r][c] == 0 :
unripe += 1
if unripe == 0 :
return 0
# 토마토 숙성시키기
while q :
h, r, c, time = q.popleft()
for dh,dr,dc in direction :
nh,nr,nc = h+dh, r+dr, c+dc
if 0<= nh < H and 0<= nr < R and 0<= nc < C and tomato[nh][nr][nc] == 0 :
tomato[nh][nr][nc] = 1
q.append((nh,nr,nc,time+1))
# 탐색 끝나면 숙성안된 토마토가 남았는지 확인
for h in range(H) :
for r in range(R) :
for c in range(C) :
if tomato[h][r][c] == 0 : # 고립된 토마토가 있다는 뜻
return -1
return time
# 입력 처리
C, R, H = map(int, input().split()) # 열, 행, 층 개수 입력
# 3차원 배열로 토마토 상태 입력 받음
tomato = [ [list(map(int, input().split())) for _ in range(R)] for _ in range(H) ]
# BFS를 수행하여 결과 출력
print(bfs())
- 위 코드를 모두 이해하긴 어려워서,
- 이미 모두 익어있는 경우를 확인할 수 있도록 unripe 를 추가해서 시도해보았지만
- 오히려 속도가 느려지기만 했다
'개발새발문제' 카테고리의 다른 글
백준 30804 과일탕후루 실버2 (투포인터, defaultdict) (0) | 2024.12.26 |
---|---|
백준 12865 평범한 배낭 (DP) (0) | 2024.12.18 |
백준 11723 집합(set, remove, discard, .copy) (0) | 2024.12.16 |
백준 1629_곱셈(파이썬 거듭제곱 내장함수 pow, 분할정복 알고리즘) (1) | 2024.12.15 |
1 대 1 가위바위보, 자릿수 더하기, 중간값 찾기 (0) | 2024.07.16 |
댓글