[BOJ] 16236 아기상어

BFS


해당 문제는 BFS + 시뮬레이션 유형이다. 가까운 거리의 먹이부터 먹는다 라는 점에서 BFS임을 확인할 수 있다. 그리고 가까운 거리란 움직이는 이동거리라고 했으므로 L1 distance가 된다. 따라서 고려해야할 조건은 다음과 같다.

  • 먹을 수 있는 물고기가 있는지?
  • 먹을 수 있는 물고기들 중 무엇을 먹을 것 인지? 우선순위는 위 → 왼쪽 순서이다.

여기서 우선순위를 고려할때 막연하게 BFS의 움직임을 위→왼→오→아래 로 한다면 틀린 답이 나올 것이다. 따라서 같은 레벨에 존재하는 먹이가 될 수 있는 물고기들에 대한 자료구조를 정의해서 우선순위가 가장 높은 곳으로 이동해야 한다.

우선순위는 heap 자료구조를 사용하여 우선순위큐를 통해 구현했다. 거리 → x(상하) → y(좌우) 좌표 순으로 key값으로 사용하도록 했다. 따라서 같은 거리에서 가장 위쪽에 있는 물고기를, 그 다음엔 가장 왼쪽에 있는 물고기를 먹을 수 있도록 하면 된다. 코드는 아래와 같다.

구현


import sys
from collections import deque
import heapq

dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]

def bfs(start, n, size):
    heap = []
    q = deque()
    q.append((start[0], start[1], 0))
    visited = [[False] * n for _ in range(n)]
    visited[start[0]][start[1]] = True
    dist = 0
    while q:
        x, y, dist = q.popleft()
        if heap:
            if heap[0][0] < dist:
                dist, x, y = heapq.heappop(heap)
                graph[x][y] = 0
                return x, y, dist
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            # 인덱스 범위 밖
            if nx < 0 or ny < 0 or nx >= n or ny >= n:
                continue
            # 벽(숫자가 큰 물고기만남)
            if graph[nx][ny] > size:
                continue
            # 이미 방문한 공간
            if visited[nx][ny]:
                continue
            # 더 작은 물고기를 만남 -> 먹잇감으로 지정
            if 0 < graph[nx][ny] < size:
                heapq.heappush(heap, (dist + 1, nx, ny))
            # 그냥 이동 경로임
            q.append((nx, ny, dist+1))
            visited[nx][ny] = True
    if heap:
        dist, x, y = heapq.heappop(heap)
        graph[x][y] = 0
        return x, y, dist
    return -1, -1, 0

def solution(n):
    # 초기 변수들 설정
    size = 2
    count = 0
    time = 0

    # 상어 위치 찾음
    start_x, start_y = 0, 0
    for i in range(n):
        for j in range(n):
            if graph[i][j] == 9:
                start_x, start_y = i, j

    # 상어가 엄마를 찾을 때 까지 반복
    while True:
        next_x, next_y, spent_time = bfs((start_x, start_y), n, size)
        graph[start_x][start_y] = 0
        # 엄마 상어 찾음
        if next_x == -1 and next_y == -1:
            break
        start_x, start_y = next_x, next_y
        time += spent_time
        count += 1      # 먹은 횟수 + 1
        if count == size:   # 상어의 크기 + 1
            count = 0
            size += 1
    return time

if __name__ == "__main__":
    N = int(sys.stdin.readline().rstrip())
    graph = []
    for _ in range(N):
        graph.append(list(map(int, sys.stdin.readline().rstrip().split())))
    print(solution(N))