백준 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. 상어는 상/하/좌/우로 1칸씩 이동한다.
  2. 이동 시간 = 이동한 칸 수
  3. 상어 크기 (size)
    • graph[nx][ny] > size : 지나갈 수 없음
    • graph[nx][ny] == size : 지나갈 수만 있음 (먹진 못함)
    • 0 < graph[nx][ny] < size : 먹을 수 있음
  4. 먹을 물고기 우선순위 1) 거리가 가장 가까운 물고기 2) 거리가 같다면 가장 위 (x가 작은) 3) 위도가 같다면 가장 왼쪽 (y가 작은)
  5. 상어가 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가 작은(왼쪽) 게 뒤로 가게