본문 바로가기
알고리즘

요세푸스 문제의 마지막 남은 사람을 수학적 귀납법으로 도출한 점화식으로 찾아보자

by Renechoi 2024. 10. 13.

이 글의 작성 배경

요세푸스 문제를 다양한 방법으로 풀어보면서 배열, 큐, 링크드 리스트, 세그먼트 트리 등 여러 알고리즘적 접근을 시도해 보았다. 각 방법에서 최적화를 시도했지만, 시간 복잡도는 여전히 \( O(n^2) \) 정도였고, 세그먼트 트리를 사용해도  \( O(n \log n) \) 이 최대였다. 조금 더 최적화할 방법이 뭔가 있을 것 같은데... 고민하다가 문제를 가상의 순환 구조로 해석하면 어떤 규칙이나 패턴이 존재하지 않을까 하는 의문이 생겼다. 그러던 중, 점화식 풀이법을 알게 되며 이 방식에 주목하게 되었다.

 

점화식을 활용한 풀이법은 흥미로웠지만, 문제는... 어려웠다. 😭 특히, 이 점화식을 어떻게 유도할 수 있는지, 그 논리적 근거와 직관이 어떻게 도출되는지, 그리고 실제로 이 점화식이 어떻게 작동하는지 물음표가 켜졌다. 이 글은 이러한 궁금증을 풀기 위해 공부하면서 작성한 내용이다.

문제 소개

요세푸스 문제는 역사적인 사건에서 유래한 고전적인 순열 문제로, 원형으로 앉은 사람들 중 특정 간격으로 사람들을 제거해 나갈 때 마지막에 남는 사람 또는 제거되는 순서를 구하는 문제이다.

 

문제 설명은 다음과 같다.

N명의 사람들이 원형으로 앉아 있고, 순서대로 K번째 사람을 제거합니다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나갑니다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속됩니다.

원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다.

 

예를 들어, (7, 3)-요세푸스 순열<3, 6, 2, 7, 5, 1, 4>이다.

점화식으로 마지막 남은 사람 구하기

문제에 따라 순열을 전부 구해야 하는 경우도 있고, 마지막 남은 사람만 구해야하는 경우도 있다. 마지막 남은 사람만 구하는 경우, 재귀식을 이용해서 효율적으로 풀 수 있다.

 

이때, 마지막 남은 사람만 구하는 경우에 대해서 원형 구조를 가진 문제에서 실제로 자료구조를 회전시키는 대신, 수학적으로 인덱스를 계산하여 문제를 해결할 수 있다.

점화식

사람들은 1번부터 N번까지 번호가 매겨져 있고, 인덱스는 계산의 편의를 위해 0부터 N-1까지 사용할 때, 재귀식은 다음과 같다.

 

\[
J(n, k) = (J(n - 1, k) + k) \mod n
\]

 

여기서

 

- \( J(n, k) \): \( n \)명의 사람이 있을 때 요세푸스 순열에서 마지막으로 남는 사람의 위치 (0부터 시작하는 인덱스)

- \( k \): 제거할 사람의 간격

 

단계별 풀이 과정 

먼저 이와 같은 점화식이 어떻게 작동하는지 데이터 흐름을 시각화해서 살펴보자.

 

1. 재귀식 수립

  • 기저 사례:

\[
J(1, K) = 0
\]

  • 재귀 관계식:

\[
J(n, K) = (J(n - 1, K) + K) \mod n
\]

 

여기서

  • \( J(n, K) \): \(n\)명의 사람이 있을 때 마지막으로 남는 사람의 위치 (0부터 시작하는 인덱스)
  • \( K \): 제거할 사람의 간격

2. 단계별 점화식 흐름

 

이제 \( N = 7 \), \( K = 3 \)인 경우에 대해 단계별로 점화식이 어떻게 작동하는지 살펴보자.

\( n \)을 1부터 7까지 증가시키면서 \( J(n, K) \)의 값을 계산한다.

 

1. n = 1 
  • 계산:
    \[
    J(1, 3) = 0
    \]
  • 설명: 사람이 한 명 남았을 때, 마지막으로 남는 사람의 위치는 0번 인덱스이다.
2. n = 2 
  • 이전 값:  \( J(1, 3) = 0 \)
  • 계산:
    \[
    J(3, 3) = (J(2, 3) + 3) \mod 3 = (1 + 3) \mod 3 = 1
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번)

- 제거되는 사람의 위치: 인덱스 ( (J(1, 3) + K - 1) \mod n = (0 + 3 - 1) \mod 2 = 0 )

- 제거된 사람: 인덱스 0 ⇒ 1번

- 마지막으로 남는 사람: 인덱스 1 ⇒ 2번

3. n = 3 
  • 이전 값:  \( J(2, 3) = 1 \)
  • 계산:
    \[
    J(3, 3) = (J(2, 3) + 3) \mod 3 = (1 + 3) \mod 3 = 1
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번)

- 제거되는 사람의 위치: 인덱스 \( (J(2, 3) + K - 1) \mod n = (1 + 3 - 1) \mod 3 = 0 \)  

- 제거된 사람: 인덱스 0 \( \Rightarrow \) 1번  

- 남은 사람들: 인덱스 1 (2번), 인덱스 2 (3번)  

- 마지막으로 남는 사람: 인덱스 1 \( \Rightarrow \) 2번  

4. n = 4
  • 이전 값: \( J(3, 3) = 1 \)
  • 계산:
    \[
    J(4, 3) = (J(3, 3) + 3) \mod 4 = (1 + 3) \mod 4 = 0
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번), 인덱스 3 (4번)

- 제거되는 사람의 위치: 인덱스 \( (J(3, 3) + K - 1) \mod n = (1 + 3 - 1) \mod 4 = 3 \)

- 제거된 사람: 인덱스 3 ⇒ 4번

- 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번)

- 마지막으로 남는 사람: 인덱스 0 ⇒ 1번

5. n = 5
  • 이전 값: \( J(4, 3) = 0 \)
  • 계산:
    \[
    J(5, 3) = (J(4, 3) + 3) \mod 5 = (0 + 3) \mod 5 = 3
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번), 인덱스 3 (4번), 인덱스 4 (5번)

- 제거되는 사람의 위치: 인덱스 \( (J(4, 3) + K - 1) \mod n = (0 + 3 - 1) \mod 5 = 2 \)

- 제거된 사람: 인덱스 2 ⇒ 3번

- 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 3 (4번), 인덱스 4 (5번)

- 마지막으로 남는 사람: 인덱스 3 ⇒ 4번

6. n = 6 
  • 이전 값: \( J(5, 3) = 3 \)
  • 계산:
    \[
    J(6, 3) = (J(5, 3) + 3) \mod 6 = (3 + 3) \mod 6 = 0
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번), 인덱스 3 (4번), 인덱스 4 (5번), 인덱스 5 (6번)

- 제거되는 사람의 위치: 인덱스 \( (J(5, 3) + K - 1) \mod n = (3 + 3 - 1) \mod 6 = 5 \)

- 제거된 사람: 인덱스 5 ⇒ 6번

- 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번), 인덱스 3 (4번), 인덱스 4 (5번)

- 마지막으로 남는 사람: 인덱스 0 ⇒ 1번

7.  n = 7 
  • 이전 값: \( J(6, 3) = 0 \)
  • 계산:
    \[
    J(7, 3) = (J(6, 3) + 3) \mod 7 = (0 + 3) \mod 7 = 3
    \]
  • 데이터 흐름:

- 현재 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 2 (3번), 인덱스 3 (4번), 인덱스 4 (5번), 인덱스 5 (6번), 인덱스 6 (7번)

- 제거되는 사람의 위치: 인덱스 \( (J(6, 3) + K - 1) \mod n = (0 + 3 - 1) \mod 7 = 2 \)

- 제거된 사람: 인덱스 2 ⇒ 3번

- 남은 사람들: 인덱스 0 (1번), 인덱스 1 (2번), 인덱스 3 (4번), 인덱스 4 (5번), 인덱스 5 (6번), 인덱스 6 (7번)

- 마지막으로 남는 사람: 인덱스 3 ⇒ 4번

최종 결과

  • 마지막으로 남는 사람의 위치: \( J(7, 3) = 3 \)
  • 실제 사람 번호: \( 3 + 1 = 4 \)번

즉, 최종 남는 사람은 4번으로 확인된다.

 

이와 같은 결과가 맞는 것인지, 순서를 추적해보면서 확인해보자.

 

 

 

 

점화식 검증하기

  • 사람들: [1번, 2번, 3번, 4번, 5번, 6번, 7번]
  • 현재 인덱스: 0

단계별 제거 과정

  1. 첫 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (\text{현재 인덱스} + K - 1) \mod \text{남은 사람 수} = (0 + 3 - 1) \mod 7 = 2
      \]
    • 제거된 사람: 인덱스 2 ⇒ 3번
    • 남은 사람들: [1번, 2번, 4번, 5번, 6번, 7번]
    • 다음 시작 인덱스: 2 (제거된 인덱스 그대로)
  2. 두 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (2 + 3 - 1) \mod 6 = 4
      \]
    • 제거된 사람: 인덱스 4 ⇒ 6번
    • 남은 사람들: [1번, 2번, 4번, 5번, 7번]
    • 다음 시작 인덱스: 4
  3. 세 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (4 + 3 - 1) \mod 5 = 1
      \]
    • 제거된 사람: 인덱스 1 ⇒ 2번
    • 남은 사람들: [1번, 4번, 5번, 7번]
    • 다음 시작 인덱스: 1
  4. 네 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (1 + 3 - 1) \mod 4 = 3
      \]
    • 제거된 사람: 인덱스 3 ⇒ 7번
    • 남은 사람들: [1번, 4번, 5번]
    • 다음 시작 인덱스: 3 \mod 3 = 0
  5. 다섯 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (0 + 3 - 1) \mod 3 = 2
      \]
    • 제거된 사람: 인덱스 2 ⇒ 5번
    • 남은 사람들: [1번, 4번]
    • 다음 시작 인덱스: 2 \mod 2 = 0
  6. 여섯 번째 제거
    • 계산:
      \[
      \text{제거할 인덱스} = (0 + 3 - 1) \mod 2 = 0
      \]
    • 제거된 사람: 인덱스 0 ⇒ 1번
    • 남은 사람들: [4번]
    • 다음 시작 인덱스: 0
  7. 마지막 남은 사람
    • 남은 사람: 4번

따라서 점화식의 계산 결과와 실제로 순열 메커니즘을 추적하며 최종 확인된 결과가 일치한 것을 볼 수 있다.

점화식 도출 과정

그런데 여전히 풀리지 않는 부분이 있다. 그것은 도대체 이러한 점화식은 어떤 원리에 의해 작동하느냐는 것이다. 즉, 이 점화식이 어떻게 도출되는지가 궁금하다.

 

재귀 관계식 \( J(n, K) = (J(n - 1, K) + K) \mod n \)이 어떻게 유도되는지, 그리고 이 관계식을 어떻게 떠올릴 수 있는지에 대해 자세히 살펴보자.

1. 요세푸스 문제의 구조 이해

요세푸스 문제는 원형으로 배열된 \( n \)명의 사람들 중에서 \( K \)번째 사람을 반복적으로 제거해 나가는 과정에서 마지막에 남는 사람의 위치를 구하는 문제이다.

  • 사람들은 원형으로 앉아 있으므로, 마지막 사람까지 제거되는 순서는 순환 구조를 가진다.
  • 이때, 사람들의 위치는 1번부터 \( n \)번까지 번호가 매겨져 있다.

2. 재귀 관계식의 기본 아이디어

재귀 관계식은 기본적으로 작은 문제를 기반으로 더 큰 문제를 해결하는 방식이다.

 

요세푸스 문제의 경우 이를 통해 \( n \)명의 사람 중 마지막으로 남는 사람의 위치를 구할 수 있다. 핵심은 \( n \)명에서 \( K \)번째 사람을 제거한다면, 남은 순열은 \( n-1 \)명에 대해서 적용되므로, 결국 남은 \( n-1 \)명의 문제로 귀결된다는 점이다. 즉, \( n \)과 \( n-1 \)의 선형적 관계에 따라, 이를 재귀적으로 풀어낼 수 있는 관계식을 설정할 수 있다. 단계적으로 살펴보자.

1) 기저 사례:

먼저, 문제를 가장 작은 형태인 \( n = 1 \)의 경우로 시작한다. 이 경우 제거할 사람도 없기 때문에 마지막으로 남는 사람은 자명하게 1번 자리이다. 따라서,

 

\[
J(1, K) = 0
\]

 

여기서 0은 편의상 1번 자리를 나타내기 위해 사용된 것이다. 즉, 남은 사람이 한 명일 때는 바로 그 사람이 승자가 된다.

2) 일반적인 재귀 과정:

그렇다면, \( n \)명이 있을 때 어떻게 문제를 풀 수 있을까? 먼저 \( K \)번째 사람을 제거한 후에는 남은 사람들이 \( n-1 \)명이 된다. 이 상황에서 다시 \( K \)번째 사람을 제거하는 문제로 귀결된다. 문제를 \( n-1 \)명의 상황으로 축소했으므로, 우리는 \( n-1 \)명에서 마지막으로 남는 사람의 위치를 알 수 있다. 이를 \( J(n-1, K) \)라고 하자.

 

그렇다면, \( n \)명에서 \( K \)번째 사람을 제거한 후 남는 사람의 위치를 어떻게 구할 수 있을까? 중요한 점은 \( K \)번째 사람을 제거함으로써 남은 사람들의 번호가 재정렬된다는 것이다. 구체적으로는, 원형 구조에서 제거된 사람 다음의 사람이 첫 번째 사람처럼 되기 때문에, 남은 사람들의 위치는 한 칸씩 앞으로 이동한다. 이 변화를 반영하기 위해서, \( J(n-1, K) \)에서 나온 결과에 \( K \)를 더한 후, \( n \)으로 나눈 나머지를 구한다. 이를 수식으로 나타내면,

 

\[
J(n, K) = (J(n-1, K) + K) \mod n
\]

 

요세푸스 문제의 본질은 제거된 사람들에 의해 남은 사람들의 번호가 계속해서 변화하는 점에 있다. 한 명이 제거될 때마다, 남은 사람들이 다시 첫 번째부터 번호가 매겨지듯 재정렬되는 것이며, 이러한 동작을 반복적으로 추적해 나가는 것이 재귀 관계식의 핵심 아이디어이다.

이를 바탕으로 재귀 관계식을 유도해보자.

3. 재귀 관계식의 유도 과정

Step 1: 작은 문제에서 큰 문제로의 전환

  • \( n - 1 \)명의 사람이 남았을 때의 마지막 생존자의 위치를 알고 있다고 가정한다.
  • 이제, 이 정보를 이용하여 \( n \)명의 사람이 있을 때의 마지막 생존자의 위치를 찾으려고 한다.

Step 2: 사람들의 번호 재정의

  • 원형 구조이기 때문에, 사람들의 위치는 제거될 때마다 변경된다.
  • 그러나, 제거되는 순서는 사람들의 상대적인 위치에 의해 결정된다.
  • 따라서, 사람들의 번호를 재정의하여 문제를 단순화할 수 있다.

Step 3: 새로운 인덱스 체계 도입

  • 제거될 때마다 남은 사람들의 번호를 0부터 시작하는 새로운 인덱스로 표현한다.
  • 이렇게 하면, 각 단계에서의 사람들의 위치를 쉽게 추적할 수 있다.

Step 4: 재귀 관계식 수립

  • \( n \)명의 사람이 있을 때 마지막 생존자의 위치를 \( J(n, K) \)라고 하자.
  • \( n - 1 \)명의 사람이 있을 때의 마지막 생존자의 위치를 \( J(n - 1, K) \)라고 하자.
  • \( n \)명의 사람이 있을 때 첫 번째로 제거되는 사람의 위치는 \( (K - 1) \mod n \)이다.
  • 이때, 제거된 후 남은 \( n - 1 \)명의 사람들의 새로운 위치는 다음과 같이 재배열된다.

Step 5: 위치 조정

  • 제거된 사람 다음 위치부터 시작하여 남은 사람들을 0부터 \( n - 2 \)까지 재인덱싱한다.
  • 그러면, \( n - 1 \)명의 사람들로 이루어진 새로운 문제로 변환된다.
  • 이 부분이 핵심이므로, 간단한 예시를 통해 살펴보자.

예를 들어, \( n = 5 \), \( K = 3 \)일 때, 원형으로 앉아 있는 5명의 사람에 대해서, 다음과 같은 배열로 시작할 것이다.

  • 사람들의 번호: [0, 1, 2, 3, 4] (0부터 시작하는 인덱스 사용)
  • 원형 배열:
  • [0] - [1] - [2] - [3] - [4] - (다시 [0]으로 연결)

이때, 제거할 사람의 위치는

 

\[
\text{제거할 위치} = (K - 1) \mod n = (3 - 1) \mod 5 = 2
\]

 

로 인덱스 2번 사람이 된다. 그렇다면, 이후의 배열에서 다음 사람을 찾아내는 작업은 실질적으로, 3번 사람부터 다시 계산해야 하는 상황과 같다. 즉, 3번 사람이 0번 인덱스가 된 상황과 동일한 문제가 되는 것이다. 따라서, 제거된 사람 다음부터 순서대로 새로운 인덱스를 부여하면,

  • 제거된 사람 다음 인덱스: 3번부터 시작
  • 새로운 번호 부여: 

    기존 인덱스 사람 번호 새로운 인덱스
    3 3 0
    4 4 1
    0 0 2
    1 1 3

 

재배열된 사람들은 [3, 4, 0, 1]가 되며, 이는 이제 \( n = 4 \)명에 대한 문제와 동일해진다.

 

이제 이를 수학적으로 표기해보면,

Step 6: 수학적 표현

  • \( n \)명의 사람들 중에서 첫 번째로 제거된 사람의 위치는 \( (K - 1) \mod n \)이다.
  • 제거 후 남은 사람들의 위치를 조정하면, \( n - 1 \)명의 사람들로 구성된 새로운 문제에서의 마지막 생존자의 위치는 \( J(n - 1, K) \)이다.
  • 원래 \( n \)명의 사람들 중에서의 위치로 변환하려면, 조정된 위치를 다시 실제 위치로 변환해야 한다.

Step 7: 실제 위치로의 변환

  • 새로운 위치에서의 생존자 위치 \( J(n - 1, K) \)를 원래 위치로 변환하려면 다음과 같이 계산한다.
  • 실제 위치:
    \[
    (J(n - 1, K) + K) \mod n
    \]
  • 여기서 \( K \)는 제거된 사람의 다음 위치로의 이동을 반영하며,  \( n \)으로 모듈러 연산을 하여 원형 구조를 유지한다.

4. 재귀 관계식 완성

따라서, 재귀 관계식 유도는 다음과 같이 완성된다.

 

\[
J(n, K) = (J(n - 1, K) + K) \mod n
\]

 

즉, 이 관계식은 \( n - 1 \)명의 사람들로 이루어진 문제의 해답을 이용하여 \( n \)명의 사람들로 이루어진 문제의 해답을 구할 수 있게 해준다.

 

이 관계식을 어떻게 떠올릴 수 있을까?

 

결국 수학적 귀납법 도출 과정과 유사하다. 작은 \( n \) 값에 대해 직접 시뮬레이션을 해보면서 제거되는 사람의 위치와 마지막으로 남는 사람의 위치 사이의 패턴을 찾고, 기저 사례에서 시작하여, \( n \)에서의 해답이 \( n - 1 \)에서의 해답과 어떻게 연결되는지 찾아내야 한다.

 

 


 

끝. 

 

 

반응형