ヨセフスの問題
人の人間が円を描くように並び、処刑されるのを待っている。最初の人をスキップし、さらに \( k-2 \) 人をスキップし(つまり、\( k-1 \) 人をスキップして \(k \)番目の人に到達する)、\(k\)番目の人を処刑する。そしてそこから、再度 \( k-1 \) 人をスキップして \(k \)番目の人を処刑する。これを延々と続け(円は徐々に小さくなっていく)、最後に残った1人を釈放する。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
再帰を使った考え方は、以下の説明がとても分かりやすかったです。
Explaining the Josephus Algorithm
ここでは、循環リストを使って愚直に考えてみます。
循環リスト
循環リスト(circularly-linked list)では、先頭と最後尾のノードを相互に連結する。循環リストには片方向のものも双方向のものもある。循環リストを辿る場合、任意のノードから出発して、好きな方向にたどっていき、最初のノードに戻ってくるまで続ける。
出典: フリー百科事典『ウィキペディア(Wikipedia)』
ヨセフスの問題を、循環リストを使いそのまま表現します。
コード
def get_Josephus_position(n, m): # 循環リストを構成するノード class Node: def __init__(self, data=None, next=None): self.set_data(data) self.set_next(next) def set_data(self, data): self.data = data def get_data(self): return self.data def set_next(self, next): self.next = next def get_next(self): return self.next answer = [] # 循環リストを作成する。 head = Node(0) prev = head for i in range(1, n): current_node = Node(i) prev.set_next(current_node) prev = current_node prev.set_next(head) # 最後の一つになるまで、循環リストからノードを一つずつ取り除く。 current_node = head counter = 0 while current_node.get_next() != current_node: counter += 1 if counter == m: counter = 0 prev.set_next(current_node.next) answer.append(current_node.get_data()) else: prev = current_node current_node = current_node.get_next() answer.append(current_node.get_data()) return answer print(get_Josephus_position(41, 3))