가로, 세로 길이가 각각 M, N인 그래프가 주어지고 그래프 내 0, 1, -1이 주어진다. 0은 익지 않은 토마토, 1은 익은 토마토, -1은 빈 칸을 의미하는데, 전체 그래프에 있는 토마토가 모두 익을 때까지 걸린 날짜를 출력하는 문제
from collections import deque
import sys
input = sys.stdin.readline
# 가로 세로, 입력값 받기
m, n = map(int, input().split())
graph = [list(map(int, input().split())) for _ in range(n)]
queue = deque()
# 4방향 상하좌우 지정
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
# 익은 토마토 있는 곳 모두 queue에 넣기
for i in range(n):
for j in range(m):
if graph[i][j] == 1:
queue.append((i, j))
def bfs():
# 큐 빌 때까지 반복
while queue:
x, y = queue.popleft()
# 4방향 탐색
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
# 주어진 범위 내 다음 칸이 익지 않은 토마토인 경우
if 0<=nx<n and 0<=ny<m:
if graph[nx][ny] == 0:
# 익은 날짜들 다음 값으로 저장 및 큐에 삽입
graph[nx][ny] = graph[x][y] + 1
queue.append((nx, ny))
day = 0
bfs()
# 그래프 내 행마다
for i in graph:
# 각 행의 값마다
for j in i:
# 시작 칸이 -1인 경우 탈출
if j == 0:
print(-1)
exit(0)
# 아니면 각 행의 최대값과 day 비교
day = max(day, max(i))
# 익은 토마토는 1부터 시작하므로 -1 해주기
print(day-1)
< 풀이 과정 >
BFS를 이용하였고, 익은 토마토가 있는 모든 위치를 큐에 표시해준다. 이후 BFS 탐색을 진행하여 주어진 범위 내 다음 방문 값이 익지 않은 토마토인 경우 큐에 삽입 후 다음 칸 값 = 현재 값 + 1 진행
주어진 그래프 내 모든 행의 데이터 각 값을 체크하여 0이 있는 경우 -1 칸이 있던 것이므로 -1을 출력하고 EXIT진행 (이를 안해주면 시간 초과)
이외는 day와 비교하여 더 큰 값을 출력해준다
이번엔 앞선 문제에 3차원으로 구성해 기존 m, n에 상자 수 H가 추가되었다.
from collections import deque
import sys
input = sys.stdin.readline
# 가로 세로 상자수, 토마토, 방문 여부 만들기
m, n, h = map(int, input().split())
tomato = [[list(map(int, input().rstrip().split())) for _ in range(n)] for _ in range(h)]
visited = [[[False]*m for _ in range(n)] for _ in range(h)]
queue = deque()
# 앞뒤 상하 좌우
dx = [-1, 1, 0, 0, 0, 0]
dy = [0, 0, -1, 1, 0, 0]
dz = [0, 0, 0, 0, -1, 1]
day = 0
def bfs():
# 큐 빌때까지
while queue:
x, y, z = queue.popleft()
# 6방향 탐색
for i in range(6):
nx = x+dx[i]
ny = y+dy[i]
nz = z+dz[i]
# 주어진 범위 내 방문하지 않고 다음 칸이 익지 않은 토마토 있는 경우
if 0<=nx<h and 0<=ny<n and 0<=nz<m and visited[nx][ny][nz] == False:
if tomato[nx][ny][nz] == 0:
# 큐에 삽입, 다음 값 + 1, 방문 처리
queue.append((nx, ny, nz))
tomato[nx][ny][nz] = tomato[x][y][z] + 1
visited[nx][ny][nz] = True
for i in range(h):
for j in range(n):
for r in range(m):
if tomato[i][j][r] == 1 and visited[i][j][r] == False:
queue.append((i,j,r))
visited[i][j][r] = True
bfs()
# 토마토 내 ROW 들 중 각 값을 체크하고 각 데이터 범위만큼 0인 것 발견하면 EXIT
for i in tomato:
for j in i:
for r in j:
if r == 0:
print(-1)
exit(0)
day = max(day, max(j))
# 익은 토마토므로 1부터 시작하니 -1해주기
print(day-1)
< 풀이 과정 >
앞선 문제를 3차원으로 풀어낸 BFS 문제. 문제 풀이 방식은 앞선 문제와 동일하고, 단지 방향이 추가되어 확인해준다.
NXN 크기의 공간에 물고기 M마리와 아기 상어가 1마리 있다. 아기 상어의 크기는 2이고 자신보다 작은 크기의 물고기만 먹을 수 있다.
아기상어가 이동할 수 있는 방법은 다음과 같다
- 더 이상 먹을 물고기 없으면 엄마 상어에게 도움 요청
- 먹을 수 있는 물고기가 1마리보다 많으면 가장 가까운 물고기 먹기(위, 왼쪽 순서로)
이때 아기상어가 엄마상어에게 도움 요청하지 않고 물고기를 먹을 수 있는 시간을 출력하기
핵심은 아기상어는 자신의 크기와 같은 수의 물고기를 먹어야 크기가 1 증가한다.
from collections import deque
import sys
input = sys.stdin.readline
# n, 그래프를 입력받아 시작점이 9인 곳의 좌표와 그래프에 상어 크기 표시하기
n = int(input())
graph = []
for i in range(n):
row = list(map(int, input().split()))
graph.append(row)
for j in range(n):
if row[j] == 9:
graph[i][j] = 2
start = [i, j]
# 상하좌우 4방향 탐색
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
def bfs(i, j):
# 방문 처리 여부 그래프 생성
visited = [[0]*n for _ in range(n)]
# 시작점 방문 처리
visited[i][j] = 1
queue = deque()
# 큐에 현위치 삽입
queue.append((i, j))
# 최소 거리 그래프로 작성
dist = [[0]*n for _ in range(n)]
# 상어가 먹은 물고기의 좌표, 거리 리스트로 저장
eat = []
while queue:
x, y = queue.popleft()
# 4방향 탐색
for d in range(4):
nx = x + dx[d]
ny = y + dy[d]
# 다음 칸이 범위내에 있고 방문하지 않았다면,
if 0<=nx<n and 0<=ny<n and not visited[nx][ny]:
# 다음 칸이 0이거나 현재 상어 크기가 더 크면
if not graph[nx][ny] or graph[nx][ny] <= graph[i][j]:
방문 처리하고 거리 + 1, 큐에 삽입
visited[nx][ny] = 1
dist[nx][ny] = dist[x][y] + 1
queue.append((nx, ny))
# 다음 칸이 0이 아닌 물고기고 현재 상어 크기보다 작으면 먹기
if graph[nx][ny] < graph[i][j] and graph[nx][ny]:
eat.append((nx, ny, dist[nx][ny]))
# 먹은게 없으면 -1 리턴
if not eat:
return -1, -1, -1
# 먹은게 있다면 거리 오름차순, y, x좌표 순서대로 오름차순 정렬후 첫 값 리턴
eat.sort(key = lambda x: (x[2], x[0], x[1]))
return eat[0][0], eat[0][1], eat[0][2]
answer = 0
size = 0
while True:
# 초기값 저장
i, j = start[0], start[1]
# 초기값 기준 bfs 탐색해 처음 먹은 물고기 나온 경우부터 탐색
x, y, dist = bfs(i, j)
# 먹은게 없다면 중단,
if x == -1:
break
# 상어 다음 위치로 이동 후 0으로 변경
graph[x][y] = graph[i][j]
graph[i][j] = 0
# 초기값 바꿔주고 먹은 횟수 증가
start = [x, y]
size += 1
먹은 수가 상어크기와 같으면 먹은 횟수 초기화, 상어크기 +1
if size == graph[x][y]:
size = 0
graph[x][y] += 1
answer += dist
print(answer)
< 풀이 과정 >
BFS로 풀이했고, 오랜만에 풀었지만 구현에 시간이 걸린 문제. 생각해야할 부분이 한 두개가 아니었다.