백준 16236번 - 아기상어
아기상어 문제 바로 가기
baekjoon 알고리즘 문제 풀이
풀이 코드
from collections import deque
n = int(input())
graph = [list(map(int, input().split())) for _ in range(n)]
dx = [0,0,-1,1]
dy = [-1,1,0,0]
x,y,size = 0,0,2
# 상어 위치 찾기
for i in range(n):
for j in range(n):
if graph[i][j] == 9:
x = i
y = j
def bfs(x,y,size):
# 이동한 위치가 graph 안에 있는지 확인하고 해당 좌표가 방문했는지 확인하기
# 해당 좌표에 있는 물고기 size가 상어 크기보다 작거나 같다면 queue에 좌표 추가
# 만약 그 좌표가 0이 아니고 상어보다 작다면 먹을 수 있는 list에 추가
# 먹을 수 있는 list를 정렬시킨 후 반환하기 = (거리,y,x) 좌표순으로 내림차순 하고 pop
distance = [[0]*n for _ in range(n)]
visited = [[0]*n for _ in range(n)]
q = deque()
q.append((x,y))
visited[x][y] = 1
tmp = []
while q:
cur_x, cur_y = q.popleft()
for i in range(4):
nx = cur_x + dx[i]
ny = cur_y + dy[i]
# 이동 가능한지 확인
if 0<=nx<n and 0<=ny<n and visited[nx][ny] == 0:
# 지나갈 수 있는 칸인가
if graph[nx][ny] <= size:
q.append((nx,ny))
visited[nx][ny] = 1
distance[nx][ny] = distance[cur_x][cur_y] + 1
# 먹을 수 있는 물고기인가?
if graph[nx][ny] < size and graph[nx][ny] != 0:
tmp.append((nx, ny, distance[nx][ny]))
return sorted(tmp, key=lambda x: (-x[2], -x[0], -x[1]))
count = 0
answer = 0
while True:
shark = bfs(x,y,size)
if len(shark) == 0:
break
nx, ny, dist = shark.pop()
# 이동한 거리만큼 시간 더하기
answer += dist
# 이전 위치 비우기(상어가 떠났으니까 빈 칸), 상어 위치 이동(물고기 먹었으니까 빈 칸)
graph[x][y], graph[nx][ny] = 0,0
# 상어 좌표를 먹은 물고기 좌표로 옮기기
x,y = nx, ny
count+=1
if count == size:
size+=1
count = 0
print(answer)
해결 전략:
- 상어는 상/하/좌/우로 1칸씩 이동한다.
- 이동 시간 = 이동한 칸 수
- 상어 크기 (size)
- graph[nx][ny] > size : 지나갈 수 없음
- graph[nx][ny] == size : 지나갈 수만 있음 (먹진 못함)
- 0 < graph[nx][ny] < size : 먹을 수 있음
- 먹을 물고기 우선순위 1) 거리가 가장 가까운 물고기 2) 거리가 같다면 가장 위 (x가 작은) 3) 위도가 같다면 가장 왼쪽 (y가 작은)
- 상어가 size 마리 먹으면 size+=1
후보 정렬해서 반환하기
return sorted(tmp, key=lambda x: (-x[2], -x[0], -x[1]))
왜 (-)를 붙이냐?
- pop()으로 마지막 요소 꺼내기
- 따라서 ‘좋은 후보’가 가장 뒤로 가도록 내림차순 정렬을 만들어야 한다.
- -x[2] : 거리(dist)가 작은 게 “뒤쪽”으로 가게 만들기
- -x[0] : x가 작은(위쪽) 게 뒤로 가게
- -x[1] : y가 작은(왼쪽) 게 뒤로 가게