이 문서는 전문적이지 않습니다.
https://www.acmicpc.net/problem/18405
18405번: 경쟁적 전염
첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치
www.acmicpc.net
입력 :
첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치에 존재하는 바이러스의 번호가 공백을 기준으로 구분되어 주어진다. 단, 해당 위치에 바이러스가 존재하지 않는 경우 0이 주어진다. 또한 모든 바이러스의 번호는 K이하의 자연수로만 주어진다. N+2번째 줄에는 S, X, Y가 공백을 기준으로 구분되어 주어진다. (0 ≤ S ≤ 10,000, 1 ≤ X, Y ≤ N)
출력 :
S초 뒤에 (X,Y)에 존재하는 바이러스의 종류를 출력한다. 만약 S초 뒤에 해당 위치에 바이러스가 존재하지 않는다면, 0을 출력한다.
"단, 매 초마다 번호가 낮은 종류의 바이러스부터 먼저 증식한다."
#1
해당 문제를 읽은 후 해결 방법으로 떠올린 알고리즘은 'BFS 너비 우선 탐색' 알고리즘이다.
너비 우선 탐색(Breadth-fist search, BFS)은 맹목적 탐색방법의 하나로 시작 정점을 방문한 후 시작 정점에 인접한 모든 정점들을 우선 방문하는 방법이다.
출처 : https://ko.wikipedia.org/wiki/%EB%84%88%EB%B9%84_%EC%9A%B0%EC%84%A0_%ED%83%90%EC%83%89
너비 우선 탐색 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전.
ko.wikipedia.org
위 알고리즘의 가장 큰 특징은 모든 레벨을 레벨 순으로 방문한다는 것이다.
이를 활용하여 문제의 '몇 초 후' 를 트리의 깊이로 생각하고 문제에 접근했다.
import sys
from collections import deque
# N : 시험관 크기 , K : 바이러스 종류
N , K = map(int, sys.stdin.readline().split())
graph = [[] for _ in range(N)] # 2차원 바이러스 그래프
q = [] # BFS를 위한 queue 세팅
for i in range(N):
graph[i] = list(map(int, sys.stdin.readline().split()))
for m in range(N):
if graph[i][m] != 0: # 각 바이러스의 처음 위치를 큐에 넣는다
q.append((graph[i][m],i,m)) # (바이러스 종류, x좌표, y좌표) 정렬을 위해 0번째 인덱스를 바이러스의 종류로 세팅
q.sort() # 바이러스 우선순위에 맞게 구별
q.append('count') # 몇 초 후를 구별하기 위한 분기점
# S : 초 , X : x좌표 , Y : y좌표
S, X, Y = map(int, sys.stdin.readline().split())
q = deque(q)
# 바이러스 전염 동선
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, +1]
while S:
now = q.popleft() # 처음 정렬을 기준으로 우선순위에 따라 바이러스가 나온다.
if now == 'count': # 만약 분기점 도달
S -= 1 # 1초 지났다.
q.append('count') # 다음 분기점을 설정한다.
continue # 반복문을 다시 시작한다.
else:
for i in range(4):
nx = now[1] + dx[i]
ny = now[2] + dy[i]
if 0 <= nx < N and 0 <= ny < N :
if not graph[nx][ny]: # 해당 좌표가 아직 전염되지 않았다면,
graph[nx][ny] = now[0] # 해당 좌표에 바이러스를 옮긴다.
q.append((now[0],nx,ny)) # 다음 전염을 위해 큐에 정보를 넣어준다.
print(graph[X-1][Y-1]) # 문제에서 제시한 좌표의 바이러스를 읽는다. 그래프에 패딩을 시키지 않았다. 그래서 각 좌표에 -1 을 더한다.
queue를 이용한 너비 우선 탐색으로 문제를 풀어나가니 수월하게 해결됐다.
고민했던 부분은 1초가 지난 시점을 컴퓨터가 알 수 있게 하는 것이었다.
#2
이 문제를 해결하기 위해서 초반 큐 세팅에서 마지막에 'count' 라는 문자열 데이터를 집어넣었다.
즉, queue.popleft() 의 값이 'count' 가 된 시점은 "1초 동안"의 바이러스 전염이 끝났다는 뜻이다.
또한, 큐 자료구조에서 'count'의 뒤에는 이미 "다음 1초 동안"의 전염데이터가 쌓여있다는 뜻이다.
1초가 지났다는 것을 알 수 있으므로 해당 정보를 갱신하고, 'count'를 다시 넣어줌으로써 "다음 분기점"을 세팅했다.
이를 반복하여 제시된 시간만큼 바이러스 전염을 진행시킬 수 있었다.
#3
'큐' 자료구조와 '너비 우선 탐색' 에 대한 학습을 한 덕분에 위 문제가 잘 해결됐다.
첫 주차에는 정말 어려웠을 문제인데, 성장해나가는 것 같아 뿌듯하다.
처음에는 내가 뭘 공부해야 하는지, 무엇을 모르는지, 무엇을 아는지 몰랐다.
아직 잘 모르겠지만, 적어도 조금은 어제보다 나아갔다는 확신이 든다.
날이 많이 추워졌습니다.
다들 따듯한 옷을 꺼내시고,
얼죽아 분들은 꼭 장갑을 착용하시기 바랍니다.
오랜만에 긴 글 읽어주셔서 감사드립니다.
22.11.18
'TIL (Today I Learned) > 코딩테스트 연습' 카테고리의 다른 글
[프로그래머스 C#] Lv.2 혼자 놀기의 달인 (0) | 2024.04.05 |
---|---|
[programmers] 같은 숫자는 싫어 (3) | 2023.09.06 |
[백준 2468번] 런타임 에러(RecursionError), Boolean Table 과 메모리. (4) | 2022.11.02 |
[백준 10819번] 리스트 복사와 메모리에 대한 고민. 재귀 함수를 활용하여 문제를 풀어보자./22.11.01 (0) | 2022.11.02 |
[백준 10989번] Counting sort, 메모리 초과, PyPy3 와 Python3 / 22.10.31 (3) | 2022.10.31 |
댓글