Algorithm/Python

[백준 16236] 아기 상어

🥭맹2 2021. 2. 3. 02:19
1. 문제

 

www.acmicpc.net/problem/16236

 

16236번: 아기 상어

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

www.acmicpc.net

2. 접근방법

 

1. 상어의 위치를 구한다

2. BFS를 이용해서 순회한다

  2-1. 이 때, 상어가 움직일 수 있는 좌표를 담은 queue(q), 먹을 수 있는 물고기를 담은 queue(eatq) 이렇게 두 개가 필요하다

  2-2. 먹을 수 있는 물고기 기준인 상어의 크기를 변수로 만든다. (level)

  2-3. 상어가 이동한 거리를 담을 변수를 만들어준다. (eat_time)

  2-4. 상어가 먹은 물고기 갯수를 담을 변수를 만들어준다. (eat_num)

3. 무한 루프를 이용한다. (while True)

  3-0. 무한 루프는 상어가 한마리의 물고기를 먹을 때까지의 루프이다.

  3-1. 따라서 무한루프의 break 조건은 먹을 물고기가 없을 때 (문제에 나온 조건임, 먹을 물고기 존재 유무는 boolean값으로 만들어서 확인)

  3-2. 무한 루프에서 방문 체크를 해준다. (visited)

    3-2-1. 왜냐하면, 한 마리를 먹기 위해 움직일 때 동선이 겹치면 안되기 때문. 한 마리 먹고 나서는 그 전에 갔던 곳 다시 가도 됨

  3-3. 현재 상어의 위치에 물고기가 존재하는 경우 !! => 바로 먹지 않고, 먹을 수 있는 물고기인지 확인(level 확인) 후 먹을 수 있는 물고기를 담은 queue에 담아준다. (이 때, 물고기까지의 거리인 cnt도 함께 담아준다.)

  3-4. 현재 상어의 위치에 물고기가 존재하지 않는 경우 !! => 4방 탐색을 통해 상어가 움직일 수 있는 좌표를 queue에 담아준다. (이 때, 거리를 의미하는 cnt도 함께 담아준다, cnt의 경우 현재 cnt에서 +1한 값)

 

  3-5. break는 여기서 해준다. (상어 이동 queue(q)가 끝났을 때)

 

  3-6. eatq를 하나씩 확인한다.

    3-6-0. 먹을 물고기를 선정해야하기 때문에, 선정을 위한 변수를 지정한다. (min_cnt, min_x, min_y) : 거리, 좌표x, 좌표y

    3-6-1. 만약 거리(cnt)가 min_cnt보다 작다면 -> 해당하는 좌표 값과 cnt으로 갱신한다.

    3-6-2. min_cnt와 거리가 같다면 -> 해당 좌표에서 y값이 더 작은지 확인 -> 작다면 갱신

    3-6-3. min_cnt와 거리도 같고, y좌표 값도 같다면 -> x값 기준으로 왼쪽에 있는지 확인 -> 왼쪽에 있다면 갱신

  3-7. 먹을 물고기가 있다면 물고기를 먹고, eat_time 을 증가시키고, eat_num(먹은 물고기 갯수)도 +1하고 이에 따라 level도 갱신해준다.(갱신 여부는 eat_num 기준) 그리고 현재 상어 위치를 해당 물고기 위치로 갱신하고 다시 q에 집어 넣어서 무한루프 시작 ~!

 

3. 파이썬 코드

 

from collections import deque

def bfs(x, y):
    global N
    dir = [[0, -1], [-1, 0], [1, 0], [0, 1]]
    q = deque()
    q.append((x, y, 0))

    eatq = deque()

    eat_time = 0
    eat_num = 0

    level = 2

    min_x = x
    min_y = y

    while True:
        eat = False
        visited = [[False] * N for _ in range(N)]
        visited[min_y][min_x] = True
        while q:
            now_x, now_y, cnt = q.popleft()
            if board[now_y][now_x] == 9:
                board[now_y][now_x] = 0

            if board[now_y][now_x] != 0 and board[now_y][now_x] < level:
                eat = True
                eatq.append((now_x, now_y, cnt))
                while q:
                    test_x, test_y, cnt = q.popleft()
                    if board[test_y][test_x] != 0 and board[test_y][test_x] < level:
                        eatq.append((test_x, test_y, cnt))
            else:
                for i in range(4):
                    test_x = now_x + dir[i][0]
                    test_y = now_y + dir[i][1]
                    if 0 <= test_x < N and 0 <= test_y < N and visited[test_y][test_x] == False and board[test_y][test_x] <= level:
                        visited[test_y][test_x] = True
                        q.append((test_x, test_y, cnt+1))

        if not eat:
            break

        min_x = -1
        min_y = -1
        min_cnt = 1e9

        while eatq:
            eat_x, eat_y, eat_cnt = eatq.popleft()
            if eat_cnt < min_cnt:
                min_cnt = eat_cnt
                min_x = eat_x
                min_y = eat_y

            elif eat_cnt == min_cnt:
                if eat_y < min_y:
                    min_cnt = eat_cnt
                    min_x = eat_x
                    min_y = eat_y

                elif eat_y == min_y:
                    if eat_x < min_x:
                        min_cnt = eat_cnt
                        min_x = eat_x
                        min_y = eat_y

        if min_x != -1:
            board[min_y][min_x] = 0
            eat_time += min_cnt
            eat_num += 1
            if eat_num == level:
                eat_num = 0
                level += 1
            q.append((min_x, min_y, 0))

    return eat_time

N = int(input())
board = [list(map(int, input().split())) for _ in range(N)]
ans = 0

for y in range(N):
    for x in range(N):
        if board[y][x] == 9:
            start_x, start_y = x, y

print(bfs(start_x, start_y))

 

 

4. 마치며

 

어제부터 어떻게 접근해야할지 몰라 고민한 문제인데 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!첫 시뮬 문제 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!여서 힘들었는데 !!!!!!!!!!!!!!!!!!!사실 처음에 그냥 BFS 이용해서 그냥 물고기 막 먹었는데 예제 4에서 나가리 되어가지고 ..잘못 접근한 것을 깨닫고 ..갓 승환님과 갓 하늘님의 도움으로 한땀한땀 정성스레 만든 코드입니다요

 

시험은 내일인데 . . . . 아니 12시간 뒤 . . . .인데 .. .  . 코드를 느껴보고자 바로 포스팅했슴다

 

약간 지금은 덜 정제되었지만 내일 다시 읽어보고 정제하는 과정을 거쳐보도록 합죠

 

www.youtube.com/watch?v=761ae_KDg_Q

 

'Algorithm > Python' 카테고리의 다른 글

[조합]  (0) 2021.03.04
[알고리즘] 순열  (0) 2021.02.07
[백준 20055] 컨베이어 벨트 위의 로봇  (0) 2021.02.02
[백준 17471] 게리맨더링  (0) 2021.02.01
[백준 17070] 파이프 옮기기 1  (0) 2021.01.31