아기 상어
문제링크
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
를 정렬하여 진행하였다.
단계 별로 설명하자면,
- 상어의 위치 찾고 queue 만들어주기 ( queue = [[이동한 거리 , 상어의 x 좌표, 상어의 y좌표, 상어의 크기, 먹은 물고기의 수]])
- 1단계 :
while
문을 사용하여 queue가 모두pop()
될때까지 반복문을 수행하였다. - 2단계: 새로
pop
된 값의 cnt 가 현재의 단계 (직전의 단계) 보다 클 경우 직전의 단계에 먹을 수 있는 물고기의 후보들을 문제에 조건에 맞게 정렬한 후 물고기를 먹는다. - 2단계: 물고기를 먹었다면
queue
와visited
를 초기화 한다. 또ans
값을 갱신한다. 그리고 3단계가 시행이 되지 않도록flag = 1
로 갱신한다. 3단계가 실행하지 못하도록 한 뒤 다음 반복문에서 1단계 부터 3단계 까지 조건에 맞게 시행될 수 있도록 다시flag = 0
으로 갱신한다. - 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