Posts [백준] #16236 아기 상어 Python (파이썬)
Post
Cancel

[백준] #16236 아기 상어 Python (파이썬)

아기 상어

문제링크

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

풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import sys
sys.stdin = open("input.txt",'r')
from collections import deque
n = int(input())
board = [[int(x) for x in input().split()] for _ in range(n)]
queue = deque()

# 상어의 좌표 찾고 queue 만들기
for i in range(n):
    flag = 0
    for j in range(n):
        if board[i][j] == 9:
            queue.append([0,i,j,2,0]) # count , 상어의 x 좌표, 상어의 y좌표, 상어의 크기, 먹은 물고기의 수
            flag = 1
            board[i][j] = 0
            break
    if flag == 1:
        break

dir = [[-1,0],[0,-1],[0,1],[1,0]]
visited = [[0]*n for _ in range(n)]

now = 0 # 단계를 비교하기 위해서
can_eat = [] # 같은 cnt 에서 상어가 먹을 수 있는 물고기의 좌표들
flag = 0 # 상어가 물고기를 먹었을 경유 visited 와 queue 를 초기화 하기 위해 '3번 단계'를 실행하지 않기 위해 존재
ans = 0 # 출력 답

while queue:
    ### 1단계
    cnt, x, y, shark_size, eat_fish_cnt = queue.popleft()

    #### 2단계 (물고기 먹어주기)
    if now < cnt: # 다음단계가 오면 그전에 먹을 수 있는 물고기 후보들 중 조건에 맞는 애를먹는다.

        if len(can_eat) > 0:
            visited = [[0]*n for _ in range(n)] # 방문지 초기화
            can_eat = sorted(can_eat, key = lambda x: (x[0], x[1])) # 가장 위에 있는에 그리고 가장 왼쪽인 애    
            nx, ny = can_eat[0]
            queue = deque() # 물고기를 먹었으니 queue 초기화
            eat_fish_cnt += 1 # 물고기 먹은 개수 늘려주기
            if shark_size == eat_fish_cnt: # 물고기를 먹은 횟수와 상어의 크기가 같다면
                shark_size += 1 # 상어의 크기를 늘려주고
                eat_fish_cnt = 0 # 먹은 횟수는 다시 0 으로 초기화
            board[nx][ny] = 0
            queue.append([cnt,nx,ny,shark_size,eat_fish_cnt])
            can_eat = []
            flag = 1 # queue 를 초기화 하였기 때문에 3번 단계를 실행하지 않고 제일 '1 단계'로 돌아가기 위해
            ans = cnt # 답 갱신

        now = cnt # 현재 단계 갱신

    #### 3단계 (4방향으로 queue 갱신)

    if visited[x][y] == 0 and flag == 0: # 2단계를 수행하지 않았고, 방문하지 않았다면
        visited[x][y] = 1
        for d in range(4): # 4방향으로 검사
            nx, ny = x+dir[d][0], y+dir[d][1]

            if -1 < nx < n and -1 < ny < n and board[nx][ny] <= shark_size and visited[nx][ny] == 0:
                if board[nx][ny] !=0 and board[nx][ny] < shark_size:
                    can_eat.append([nx,ny]) # 먹을 수 있는 물고기 후보들 추가
                queue.append([cnt+1,nx,ny,shark_size,eat_fish_cnt])

    flag = 0 # 2단계 종료후 flag = 1 인 상태인데 다시 queue에 대한 3단계를 실행하기 위해 flag 초기화

print(ans)

해설

아기 상어는 BFS 로 풀었고 중요한 것은 같은 단계 (이동한 거리가 같은) 리스트의 모음들에서 먹을 수 있는 물고기의 좌표를 비교한 후 문제의 조건에 맞게 가장 위 > 가장 왼쪽 인 애를 can_eat 를 정렬하여 진행하였다.

단계 별로 설명하자면,

  1. 상어의 위치 찾고 queue 만들어주기 ( queue = [[이동한 거리 , 상어의 x 좌표, 상어의 y좌표, 상어의 크기, 먹은 물고기의 수]])
  2. 1단계 : while 문을 사용하여 queue가 모두 pop() 될때까지 반복문을 수행하였다.
  3. 2단계: 새로 pop 된 값의 cnt 가 현재의 단계 (직전의 단계) 보다 클 경우 직전의 단계에 먹을 수 있는 물고기의 후보들을 문제에 조건에 맞게 정렬한 후 물고기를 먹는다.
  4. 2단계: 물고기를 먹었다면 queuevisited를 초기화 한다. ans 값을 갱신한다. 그리고 3단계가 시행이 되지 않도록 flag = 1 로 갱신한다. 3단계가 실행하지 못하도록 한 뒤 다음 반복문에서 1단계 부터 3단계 까지 조건에 맞게 시행될 수 있도록 다시 flag = 0 으로 갱신한다.
  5. 3단계: 먹을 수 있는 물고기가 없거나, 아직 이전과 같은 단계라면 (cnt == now) 4방향으로 queue 를 갱신한다.

아래의 예시와 같이 먹을 수 있는 물고기는 있지만, 아예 도달할 수 없어 시도조차 하지 못하는 경우가 있습니다. 아래의 반례가 문제를 이해하고 통과하는데 많은 도움이 되었으니 테케를 통과했음에도 틀린 분들은 참고하는 것이 좋을 것 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 도움이 된 반례
#input
3
9 2 2
2 2 3
1 3 1

#output
2

#input
2
9 3
3 1

#output
0
This post is licensed under CC BY 4.0 by the author.

[Network] 데이터 송수신하는 프로토콜 스택

[OS] 교착 상태(deadlock)의 개념과 발생 원인

Loading comments from Disqus ...