BOJ 16920 확장 게임
접근 방법
우선 문제 설명대로 각 플레이어마다 확장을 하는 것을 반복하면 된다고 생각했다.
이때 문제점은 다음과 같다.
1) 플레이어가 허용된 거리까지만 확장해야 하는 것
2) 각 플레이어가 이전 턴에서 확장한 성들의 위치를 기억해야 한다는 것
문제 조건에서 메모리 제한이 충분하기 때문에 문제를 간단하게 풀기 위해 메모리에 대한 신경을 쓰지 않았다.
혀용된 거리까지만 확장하게 하기 위해서 queue에 이동한 거리도 포함시켰다. 이때, 그럼 queue에서 허용된 거리의 최대치까지 온 좌표가 pop될 때, 어떻게 할 것인가가 두 번째 문제로 이어진다. $\rightarrow$ 최대치까지 이동한 좌표가 나오기 시작한다는 것은 BFS 특성 상 그 뒤에 queue에 있는 좌표들도 모두 최대치까지 이동한 좌표들이라고 생각했다.
따라서 최대치까지 이동한 좌표가 나오자마자 while 문을 끝냈다.
그러면 queue에 남아있는 좌표들은 어떻게 해야 할까?
$\rightarrow$ queue에 남아있는 값들은 최대치까지 확장된 성들의 위치가 된다. 이로써 두 번째 문제를 해결했다. queue 값들을 player 별로 저장하면 된다
이 사고 과정으로 코드를 구현했다.
이때, 배우게 된 것이 python에서 pointer를 사용하는 것이다. List의 원소가 list라고 할 때 element = list[n]으로 불러오면 element에 복사된 것이 아니라 element는 list를 참조하게 되는 것이다.
queues = [deque() for _ in range(p+1)]에서 각 deque 값을 bfs 할 때마다 update하기 위해 queues[player]에 남은 q로 update했는데 이러면 효율적이지 않다.
처음부터 q = queues[player]을 해서 q가 player의 queue을 지목하게 한 뒤 q를 update하면 된다.
정답 코드
import sys
from collections import deque
input = sys.stdin.readline
'''
각 플레이어마다 확장을 한번 하고 난 뒤의 queue을 저장해놓고 다시 자기의 턴이 되면 그 queue을 그대로 bfs
'''
n,m,p = map(int, input().split())
s = [0] + list(map(int, input().split()))
maps = []
for _ in range(n):
maps.append(list(input().rstrip()))
moves = [(0,1),(0,-1),(1,0),(-1,0)]
is_placed = [[0]*m for _ in range(n)]
#각 플레이어들의 queue
queues = [deque() for _ in range(p+1)]
#각 플레이어가 확장한 수
placed_nums = [0]*(p+1)
for i in range(n):
for j in range(m):
if maps[i][j]!='#' and maps[i][j]!='.':
queues[int(maps[i][j])].append((i,j,0))
is_placed[i][j] = int(maps[i][j])
placed_nums[int(maps[i][j])] += 1
# for place in is_placed:
# print(place)
# print('=========')
'''
expand 만큼 확장하고 끝내기. 남은 지점들은 queue에 저장
확장된 곳은 is_placed에 저장
하나도 확장을 하지 못한다면 0, 확장이 가능하다면 1을 출력
'''
def bfs(player, queue, expand, turn):
q = deque(queue)
expanded_once = False
while q:
h,w,times = q.popleft()
#expand 만큼 확장해서 생긴 castle이 존재하게 된다면 끝내기
if times == expand*turn:
q.appendleft((h,w,times))
break
for dh,dw in moves:
new_h, new_w = h+dh, w+dw
#벽이 아니고 빈 곳일 때만 확장이 가능
if 0<=new_h<n and 0<=new_w<m and (maps[new_h][new_w]=='.' and is_placed[new_h][new_w]==0):
q.append((new_h, new_w, times+1))
is_placed[new_h][new_w] = player
placed_nums[player]+=1
expanded_once = True
queues[player] = q
# for place in is_placed:
# print(place)
# print('=========')
if expanded_once:
return 1
else:
return 0
turns = 1 # turn 수
did_expand = 0 # 모든 플레이어들이 확장했는지 확인
expanded = [True]*(p+1) #전 turn에 확장했는지 확인
while True:
for player in range(1,p+1):
#전에 확장하지 못했다면 넘기기
if not expanded[player]:
continue
result = bfs(player, queues[player], s[player], turns)
if result == 1:
did_expand+=1
expanded[player] = True
else:
expanded[player] = False
#확장이 아무도 안 되었다면
if did_expand == 0:
break
#한명이라도 확장이 되었다면
else:
turns+=1
did_expand = 0
print(*placed_nums[1:])