
자료구조 문제 중에서 굉장히 훌륭한 문제로 평가받는 문제다. 이 문제를 단순히 자료구조의 입장에서 풀지 않고, 쉬운 방법부터 시작해서 이를 자료구조로 이어지게 하는 풀이로 풀어보고자 한다.
이 문제는 원을 따라서 계속 사람을 뽑아내는 문제다. 남은 사람들에 한하여
만약 이 문제를 처음으로 맞닥뜨렸다면 우선 아래의 구현 문제점을 생각해 볼 수 있다. 편의상 문제의 예시와 같이
- 어떻게 첫
번째 사람을 찾을 것인가K - 뽑힌 것을 어떻게 처리할 것인가
- 여러 번 뽑힌 이후로는 어떻게
번째 사람을 찾을 수 있는가K
일단 하나씩 파헤쳐보자.
1. 어떻게 첫 K 번째 사람을 찾을 것인가
이 부분은 배열을 배웠다면 쉽게 구현할 수 있을 것이다. 먼저 배열을 만든 후,

2. 뽑힌 것을 어떻게 처리할 것인가 & 3. 여러 번 뽑힌 이후로는 어떻게 K 번째 사람을 찾을 수 있는가
문제는 여기서부터 시작된다. 다음 것을 뽑아야 하는데 이미 뽑힌 사람들이 있기 때문에 이를 처리할 방법이 필요하다. 이는 또 다른 배열을 이용하여 처리한다. 뽑혔는지 안 뽑혔는지를 True 또는 False로 처리하여, True인 사람을 3번 지나칠 때까지 이 7명의 배열을 계속 돌린다. 마지막으로 모두 뽑힌 것이 확인될 때, 알고리즘이 종료된다.

이 방법은 확실히 풀 수 있는 방법이지만, 너무나도 복잡하다는 단점이 존재한다. 즉, 원형으로 앉아있기 때문에 사용되는 나머지 연산인
하지만 이러한 방법을 쉽게 풀 수 있는 자료구조가 있으니, 바로 큐(Queue)다. FIFO(First In First Out)의 방식을 따르는 자료구조로써, 리스트에 처음 들어간 데이터가 가장 먼저 나오는 자료구조다. 처음 빨려진 음료가 가장 먼저 입으로 도착하는 빨대를 생각하면 쉽다.
이 문제를 queue를 이용해서 다시 풀어본다면 아래와 같이 풀 수 있다.

기존의 방법과는 달리 하나의 배열에서 모든 연산이 끝나며, 더욱더 직관적으로 풀이가 와닿음을 볼 수 있다. 그러나 푸는 방법은 사실상 처음의 접근법과 같다고 보면 된다!
import sys
from collections import deque
if __name__ == '__main__':
N, K = map(int,sys.stdin.readline().rstrip().split())
now_queue = deque(list(range(1, N+1)))
josephus_list = list()
while now_queue:
for _ in range(K-1):
now_queue.append(now_queue.popleft())
# now_queue.rotate(-(K-1))
josephus_list.append(now_queue.popleft())
print('<', ', '.join(str(i) for i in josephus_list), '>', sep='')
파이썬에서는 큐를 나타내는 자료구조를 collections 패키지의 deque를 통해 사용할 수 있다. 물론 queue를 직접 구현하는 방법이 있지만 만약 queue라는 구조를 알기 위해 한 번 구현해 봤다면 굳이 그럴 필요까진 없다.
우리는 queue를 써야하므로 popleft & append 또는 pop & appendleft 둘 중 하나를 써야 한다. 이유는 queue는 단방향성을 가지기 때문이다. 개인적으로는 queue로 쓸 때 popleft & append를 사용한다. 여담으로 deque는 단어에서 de가 말하는 의미에서 보듯 양방향성 queue다.
'Python > 백준 문제 풀이' 카테고리의 다른 글
[BOJ] 11536번 줄 세우기 (0) | 2023.03.17 |
---|---|
[BOJ] 27648번 증가 배열 만들기 (0) | 2023.03.09 |
[BOJ] 2468번 안전영역 (0) | 2023.01.29 |
[BOJ] 27162번 Yatch Dice (0) | 2023.01.23 |
[BOJ] 1331번 나이트 투어 (0) | 2023.01.14 |
댓글