알고리즘

[백준] 16326. 아기 상어

담쏙 2021. 10. 20. 23:31
728x90

https://www.acmicpc.net/problem/16236

 

16236번: 아기 상어

N×N 크기의 공간에 물고기 M마리와 아기 상어 1마리가 있다. 공간은 1×1 크기의 정사각형 칸으로 나누어져 있다. 한 칸에는 물고기가 최대 1마리 존재한다. 아기 상어와 물고기는 모두 크기를 가

www.acmicpc.net

bfs 구현 문제로, 이 문제를 풀 때 주의해야할 점이 몇 가지 있다.

 

1. 아기 상어의 위치를 나타내주는 9를, 아기상어를 찾은 즉시 0(빈칸)으로 바꿔주어야 한다. 그렇지 않으면 9 크기의 물고기가 있다고 인식해버린다.

 

2. 먹을 수 있는 물고기를 저장하는 리스트를 따로 만들어서 거리가 같은 모든 물고기를 넣어야 하며, 물고기가 위치한 거리보다 먼 곳은 탐색하지 않도록 조건을 제대로 주어야 한다.

 

3. maps에 저장된 숫자가 아기 상어 크기보다 작은 것만 체크해서는 안 되고, 해당 위치가 빈칸인지 아닌지도 확인해주어야 한다.

 

4. 아기 상어 위치를 계속 갱신하며 while 문을 돌려주어야 한다. while이 아니라 다른 방법으로 구현하려고 하면 더 복잡해진다.

 

이 외의 자세한 구현 방법은 아래 코드의 주석으로 달아놓았다.

import sys
from collections import deque
input = sys.stdin.readline

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


def bfs(y, x):
    global ans
    global baby_shark
    start_y, start_x = y, x
    # 아기 상어 위치 0으로 초기화
    maps[start_y][start_x] = 0
    # 먹은 물고기 수
    eat = 0
    while True:
        # q에 아기상어 위치, 거리 저장
        q = deque([[start_y, start_x, 0]])
        # 물고기 위치 저장
        fish_pos = []
        # 가까운 몰고기 거리 저장 (일단 최대로 초기화)
        fish_dist = n*n+1
        # 새로운 아기 상어 위치마다 visited 배열 초기화
        visited = [[0]*n for _ in range(n)]
        visited[start_y][start_x] = 1
        while q:
            r, c, dist = q.popleft()
            for k in range(4):
                ny = r + dy[k]
                nx = c + dx[k]
                # 맵을 벗어나지 않고, 방문하지 않았으며, 아기상어 크기보다 크거나 같을 경우
                if 0 <= ny < n and 0 <= nx < n and not visited[ny][nx] and maps[ny][nx] <= baby_shark:
                    # 일단 방문
                    visited[ny][nx] = 1
                    # 만약 아기상어와 크기가 같거나, 물고기가 없음
                    # 그리고 그곳으로 도달하는 거리가 현 상태에서 먹을 수 있는 물고기의 거리보다 작을 경우
                    if (maps[ny][nx] == baby_shark or not maps[ny][nx]) and fish_dist > dist + 1:
                        q.append([ny, nx, dist+1])
                    # 만약 먹을 수 있는 물고기일 경우
                    if 0 < maps[ny][nx] < baby_shark:
                        # 현재 저장된 물고기 거리가 지금 거리보다 멀 경우
                        if fish_dist > dist+1:
                            fish_dist = dist+1
                            fish_pos = [[ny, nx]]
                        # 현재 저장된 물고기 거리와 지금 거리가 같을 경우
                        elif fish_dist == dist + 1:
                            fish_pos.append([ny, nx])
        
        # while 문 탈출 후 (먹을 수 있는 물고기 탐색 완료 후)
        # 먹을 수 있는 물고기가 있을 경우
        if len(fish_pos) > 0:
            # 거리가 가까운 물고기 많다면 가장 위, 왼쪽에 있는 물고기 먹기
            fish_pos.sort()
            # sort 후 가장 첫번째 물고기 먹음
            ny, nx = fish_pos[0]
            # 물고기까지의 거리 저장 (지난 시간 == 물고기와의 거리)
            ans += fish_dist
            # 먹은 물고기 추가
            eat += 1
            # 먹은 물고기 없애줌
            maps[ny][nx] = 0
            # 만약 아기상어 크기와 먹은 물고기 수가 같다면
            if eat == baby_shark:
                baby_shark += 1
                eat = 0
            # 아기 상어 위치 갱신
            start_y = ny
            start_x = nx
        # 없으면 엄마상어에게 도움 요청 (함수 탈출!)
        else:
            return


n = int(input())
# 1, 2, 3, 4, 5, 6 : 물고기 크기
# 9 아기 상어 위치
maps = [list(map(int, input().split())) for _ in range(n)]
baby_shark = 2
ans = 0

for i in range(n):
    for j in range(n):
        if maps[i][j] == 9:
            bfs(i, j)
            break


print(ans)

'알고리즘' 카테고리의 다른 글

[백준] 19237. 어른 상어  (0) 2021.10.23
[백준] 19236. 청소년 상어  (0) 2021.10.22
[백준] 17619. 개구리 점프  (0) 2021.10.19
[백준] 1197. 최소 스패닝 트리  (0) 2021.10.19
[백준] 14621. 나만 안되는 연애  (0) 2021.10.19