구체수학 01.재귀적인 문제들.03.요세푸스 문제
01.RECURRENT PROBLEMS
- 일러두기
- 1.3 요세푸스 문제(THE JOSEPHUS PROBLEM)
- Links
일러두기
- 이 문서는 (책) CONCRETE MATHEMATICS(구체수학)책의 1장을 공부하며 메모한 것입니다.
- 이 문서는 메모일 뿐이니 자세한 내용은 교재를 참고해야 합니다.
1.3 요세푸스 문제(THE JOSEPHUS PROBLEM)
1세기의 역사가 플라비우스 요세푸스(Flavius Josephus)의 이름을 딴 문제를 변형한 문제.
- 제 1차 유대-로마 전쟁 중, 41명의 유대인 반역자들을 한 동굴에 모아놓았다.
- 반역자들은 갇혀있기 싫어서 자살을 하기로 결심하였다.
- 자살하는 방식은 다음과 같다.
- 둥글에 원을 그리고 앉는다.
- 원을 따라 두 번째 사람을 죽인다.
- 모두가 죽을 때까지 이를 반복한다.
- 그런데 두 사람(요세푸스와 그의 친구)은 죽고 싶지 않았다.
요세푸스와 친구는 원의 어느 위치에 있어야 살아남을 수 있을까?
최초에 n
명이 원에 앉아 있을 때, 마지막에 살아남는 사람의 번호를 J(n)
이라 하자.
그렇다면 위의 문제는 임의의 n
에 대하여 J(n)
의 값을 구하는 문제로도 볼 수 있다.
값을 미리 계산할 수 있다면, 살아남는 자리를 차지하여 죽지 않을 수 있다.
작은 사례부터 생각하자
n = 10
인 경우부터 생각해보자.
1
부터 세어나가며 죽인다고 할 때 죽이는 순서는2, 4, 6, 8, 10, 3, 7, 1, 9
이다.- 따라서,
J(10) = 5
추측 : J(10) = 5
이니까, J(n)=n2J(n)=n2이 아닐까?
n
이 작을 때 n
과 J(n)
과의 관계를 간단히 표로 정리해 보자.
n | J(n) | 죽는 순서 |
---|---|---|
1 | 1 | |
2 | 1 | 2 |
3 | 3 | 2, 1 |
4 | 1 | 2, 4, 3 |
5 | 3 | 2, 4, 1, 5 |
6 | 5 | 2, 4, 6, 3, 1 |
곰곰히 살펴보면 다음과 같은 사실을 알 수 있다.
J(3) = 3
이고,J(4) = 1
이므로 위의 추측은 틀렸다.2, 4, 6...
과 같이 첫 루프에서는 짝수 번호가 전부 죽는다는 것을 알 수 있다.- 따라서
J(n)
은 항상 홀수이다. n
이 짝수이면, 첫 루프에서 짝수가 전부 죽고 인원수가 절반이 된다.- 즉 시작 인원 수가
2n
인 경우, 첫 루프가 끝난 후의 인원 수는n
이 된다.
- 즉 시작 인원 수가
n이 짝수인 경우
시작 인원 수가 2n
인 경우가 쉬워보이니 이것부터 생각해보자.
1, 2, 3, 4...
가 1, 3, 5, 7...
이 된 셈이므로, 각 번호에 2를 곱하고 1을 뺀 것
과 똑같은 모양이 되었다.
그렇다면 다음과 같이 표현할 수 있을 것이다.
J(2n)=2J(n)−1,forn≥1이제 J(10)
의 값이 5 라는 것을 알고 있기 때문에 J(20)
의 값도 구할 수 있게 되었다.
n이 홀수인 경우
n이 홀수인 경우는 어떻게 될까?
- 사람의 수가
2n + 1
만큼 있다고 가정하자. - 일단 첫 루프에서는
2, 4, 6, 8, ... 2n
과 같이 모든 짝수 번호가 죽는다. - 그리고 마지막
2n + 1
번째 사람을 건너뛰게 되므로, 두 번째 루프에서는1
이 가장 먼저 죽는다.
아무래도 두 번째 루프가 시작되고 1
이 죽고 난 다음까지를 첫 번째 루프로 생각하는 쪽이 쉬울 것 같다.
그렇다면 새로 정의한 첫 번째 루프가 끝난 직후는 다음과 같을 것이다.
1, 2, 3, 4...
가 3, 5, 7, 9...
가 된 셈이므로, 각 번호에 2를 곱하고 1을 더한 것
과 같은 모양이 되었다.
그러므로, 짝수인 경우와 비슷하게 식을 표현할 수 있다.
J(2n+1)=2J(n)+1,forn≥1점화식
위에서 얻어낸 식을 토대로 다음과 같은 점화식을 만들 수 있다.
J(1)=1;J(2n)=2J(n)−1,forn≥1J(2n+1)=2J(n)+1,forn≥1python으로 표현하면 다음과 같다.
def J(n):
if n == 1:
return 1
if n % 2 == 0:
return 2 * J( n/2 ) - 1
else:
return 2 * J( (n-1)/2 ) + 1
이 점화식은 루프를 돌 때마다 n
이 거의 절반으로 줄어들게 되므로 효율적이다.
그러나 생사가 달린 문제이므로 더 빠르게 계산할 수 있는 닫힌 형태의 해를 구하고 싶다. (재귀를 들어내고 O(1) 함수를 만들고 싶다)
해를 구해보자
점화식을 사용해 다음과 같은 표를 쉽게 찾아낼 수 있다.
## 다음 코드를 실행해도 볼 수 있다
for i in range(1, 17):
print(i, J(i))
n | J(n) | |
---|---|---|
1 | 1 | |
2 | 1 | 2J(1) - 1 |
3 | 3 | 2J(2) + 1 |
4 | 1 | 2J(2) - 1 |
5 | 3 | 2J(2) + 1 |
6 | 5 | 2J(3) - 1 |
7 | 7 | 2J(3) + 1 |
8 | 1 | 2J(4) - 1 |
9 | 3 | 2J(4) + 1 |
10 | 5 | 2J(5) - 1 |
11 | 7 | 2J(5) + 1 |
12 | 9 | 2J(6) - 1 |
13 | 11 | 2J(6) + 1 |
14 | 13 | 2J(7) - 1 |
15 | 15 | 2J(7) + 1 |
16 | 1 | 2J(8) - 1 |
J(n)
은 홀수이며,1
로 시작하고,2
씩 증가한다.n
이2
의 거듭제곱일 때마다J(n)
의 값은1
이 된다.
따라서 n
을 n=2m+l로 생각할 수 있다. (단, m≥0 이고, 0≤l<2m)
그렇게 되면 각 n
은 다음과 같이 대응된다.
n | 2m+l | n | 2m+l | n | 2m+l | n | 2m+l |
---|---|---|---|---|---|---|---|
1 | 20+1 | 2 | 21+0 | 4 | 22+0 | 8 | 23+0 |
3 | 21+1 | 5 | 22+1 | 9 | 23+1 | ||
6 | 22+2 | 10 | 23+2 | ||||
7 | 22+3 | 11 | 23+3 | ||||
12 | 23+4 | ||||||
13 | 23+5 | ||||||
14 | 23+6 | ||||||
15 | 23+7 |
점화식이 다음과 같으므로,
J(1)=1;J(2n)=2J(n)−1,forn≥1J(2n+1)=2J(n)+1,forn≥1다음과 같은 식을 세울 수 있다.
J(2m+l)=2l+1,form≥0and0≤l<2m이제 수학적 귀납법으로 이 식을 증명하자.
짝수인 경우
- 2m+l=2k 인 경우를 생각해 보자.
- l은 홀수일 수 없으므로, 짝수이다.
J(2k)=2J(k)−1 이고, 2m+l=2k 이므로, 다음과 같이 식을 꾸밀 수 있다.
J(2m+l)=2J(2m+l2)−1=2J(2m−1+l2)−1그런데 J(2m+l)=2l+1 이므로,
J(2m−1+l2)=2l2+1 이다.
따라서 다음과 같은 결과가 나온다.
J(2m+l)=2J(2m−1+l2)−1=2(2l2+1)−1=2l+1이는 위에서 추측한 식과 맞아 떨어진다.
홀수인 경우
홀수인 경우는 책에 안 나오지만 해보도록 하자.
- 2m+l=2k+1 인 경우를 생각해 보자.
- l은 짝수일 수 없으므로, 홀수이다.
- J(2k+1)=2J(k)+1 이고,
- 2m+l=2k+1 이고,
- k=2m+l−12 이므로,
다음과 같이 식을 꾸밀 수 있다.
J(2k+1)=2J(k)+1J(2m+l)=2J(2m+l−12)+1=2J(2m−1+l−12)+1그런데 J(2m+l)=2l+1 이므로,
J(2m−1+l−12)=(l−1)+1=l 이다.
따라서 다음과 같은 결과가 나온다.
J(2m+l)=2J(2m−1+l−12)+1=2l+1이 또한 위에서 추측한 식과 맞아 떨어진다.
2진법으로 풀면 쉽게 풀린다?
n
을 다음과 같이 표현할 수 있을 것이다.
위의 n
을 다음과 같이 이진수 전개하는 것도 생각해 볼 수 있는 일이다.
- 단, 각 bi 는
0
또는1
이다. - 단, 제일 앞 비트인 bm 은
1
이다.
한편, n=2m+l 이므로 다음과 같이 표현할 수 있다.
- n=(1bm−1bm−2...b1b0)2
- l=(0bm−1bm−2...b1b0)2
- l=nmod2m 이기 때문에, n의 제일 앞자리를 0 으로 바꾼 값이 l이다.
- 2l=(bm−1bm−2...b1b00)2
2l
은l << 1
과 같으므로, 제일 오른쪽에 0 을 추가해주면 된다.
- 2l+1=(bm−1bm−2...b1b01)2
J(n)=2l+1 이므로 다음과 같이 정리할 수 있다.
J(n)=2l+1=(bm−1bm−2...b1b01)2=(bm−1bm−2...b1b0bm)2그런데 n=(1bm−1bm−2...b1b0)2 이므로, 다음이 증명된다.
J(n)=(bm−1bm−2...b1b0bm)2J((bmbm−1bm−2...b1b0)2)=(bm−1bm−2...b1b0bm)2즉, n을 왼쪽으로 1회 비트 순환시키면 J(n)
이 나온다.
단, 가장 왼쪽 비트가 0
일 경우엔 가장 왼쪽 비트를 삭제해 주어서, 제일 앞 비트를 1
로 유지해 주어야 한다.
아름답다.
놀라움을 음미하기 위해 몇 가지 경우를 생각해 보자.
n = 13
인 경우13 = 8 + 4 + 1
이므로,1101(2)
이다.- 이를 회전시키면
1011(2) = 11
이 나온다.
n = 100
인 경우100 = 64 + 32 + 4
이므로,1100100(2)
이다.- 이를 회전시키면
1001001(2) = 64 + 8 + 1 = 73
이다. - 100=26+36 이므로, l=36 이고, 2l+1에 의해
73
이 맞다.
최초의 추측 J(n) = n/2 를 생각해보자
즉 함수 J(n)
은 다음과 같은 작업을 한다.
n
의 제일 왼쪽에 있는1
을 가장 오른쪽으로 옮긴다.1
을 옮긴 결과, 제일 왼쪽에0
또는00...
이 있다면 삭제한다.- 결과는 항상
1
로 시작해야 하기 때문이다.
- 결과는 항상
문제는 어느 정도 풀었지만, 함수 J(n)
을 재귀시키는 경우를 생각해보자.
- 함수
J(J(J(...J(n)...)))
과 같이 재귀시키면, 충분히 많이 돌릴 경우0
은 전부 사라지고1
만 남게 될 것이다.
예를 들어 101101101101011(2)
를 충분히 회전시키면 0
이 전부 삭제되어 1111111111(2) = 1023
이 남게 될 것이다.
- 이제 최초의 추측 J(n)=n2 에 대해 생각해보자.
- 이 추측은 틀린 가설이었다.
- 이제는 해가 있으니 해를 사용하면 이 추측이 참인 경우를 판정 가능하다.
즉, l=2m−23 이 정수
인 경우에 한하여 추측은 들어맞게 된다.
다음은 J(n)=n2 를 만족시키는 몇몇 경우이다.
m | l | n=2m+l | J(n)=2l+1=n2 | n(이진수) |
---|---|---|---|---|
1 | 0 | 2 | 1 | 10 |
3 | 2 | 10 | 5 | 1010 |
5 | 10 | 42 | 21 | 101010 |
7 | 42 | 170 | 85 | 10101010 |
- 이진수를 보면 흥미로운 패턴을 보인다.
일반화 : 레퍼토리법(repertoire method)
f(n) 으로 일반화해보자
이제 J(n)
과 비슷한 함수를 만나게 되었을 때에도 쉽게 풀 수 있도록 J(n)
함수를 일반화해보자.
J(n)
의 점화식은 다음과 같았다.
이를 일반화하기 위해 상수 α,β,γ를 도입한 함수 f(n)
을 만들어 보자.
n 이 작은 경우에 대한 테이블도 만들어 보자.
nf(n)1α22α+1β32α+1γ44α+3β54α+2β+1γ64α+1β+2γ74α+3γ88α+7β98α+6β+1γ- α의 계수는
n
미만의 가장 큰 2의 거듭제곱으로 보인다. - β의 계수는
1
씩 감소해,0
까지 가는 것 같다. - γ의 계수는
0
에서 출발하여1
씩 증가하는 것 같다.
발견한 특징들을 사용해 다음과 같이 표현해보자.
n=2m+l(이전과 같다)f(n)=A(n)α+B(n)β+C(n)γ그리고 다음과 같은 추측을 할 수 있다.
식 1.14
A(n)=2mB(n)=2m−1−lC(n)=l수학적 귀납법으로 이를 증명하는 것은 생략하자. (별로 배울 것이 없다고 한다)
대신, α=1,β=0,γ=0 인 경우에 한해 생각해보자.
A(1)=1;A(2n)=2A(n),forn≥1A(2n+1)=2A(n),forn≥1그리고 다음의 사실도 알 수 있다.
A(n)=2mA(2m+l)=2m점화식에 f(n)을 적용해보자
f(1)=α;f(2n)=2f(n)+β,forn≥1f(2n+1)=2f(n)+γ,forn≥1f(n) = 1 인 경우
위의 점화식에 f(n) = 1
을 대입해 보자.
- 첫번째 식은 다음과 같이 정리된다.
- 두번째 식은 다음과 같다.
f(n)
은n
이 무엇이건 간에1
을 리턴하므로,f(2n)
도1
이라는 점을 활용한다.
- 세번째 식은 다음과 같다.
따라서, α=1,β=−1,γ=−1 이다.
이를 f(n)=A(n)α+B(n)β+C(n)γ에 적용해 보면, 다음과 같이 된다.
f(n)=A(n)−B(n)−C(n)=1f(n) = n 인 경우
위에서 한 것과 비슷하게 f(n) = n
인 경우를 생각해보자.
- 첫번째 점화식은 다음과 같이 정리된다.
- 두번째 식은 다음과 같다.
- 세번째 식은 다음과 같다.
따라서, α=1,β=0,γ=1 이다.
이를 f(n)=A(n)α+B(n)β+C(n)γ에 적용해 보면, 다음과 같이 된다.
f(n)=A(n)+C(n)=n종합
이것으로 증명은 끝났다.
결과를 종합하면 다음과 같다!
A(n)=2m,wheren=2m+land0≤l<2m;A(n)−B(n)−C(n)=1;A(n)+C(n)=n;이러한 방식으로 점화식을 풀어내는 것을 레퍼토리법(repertoire method)이라 부른다.
레퍼토리법에서는 우선 알고 있는 해에 대한 일반적인 매개변수들의 설정들을 구한다. 그러면 우리가 풀 수 있는 특별한 경우들에 대한 레퍼토리가 마련된다. 그런 다음에는 특별한 경우들을 결합해서 일반적인 경우를 얻는다. 이를 위해서는 독립 매개변수 개수(지금 예에서는 α,β,γ 세 개)만큼의 개별적인 특수해들이 필요하다.
일반식을 얻어낸 김에 식1.14를 확인해보자.
식 1.14는 다음과 같은 추측이었다.
A(n)=2mB(n)=2m−1−lC(n)=lA(n)
은 자명하므로 따로 확인할 필요가 없다.B(n)
은 다음과 같이 볼 수 있다.
C(n)
은 다음과 같이 볼 수 있다.
일반화된 점화식에 2진법 방법 적용하기
2진법으로 풀면 쉽게 풀린다에서 구했던 2진법 J
점화식을 다시 떠올려 보자.
bm=1일 때,
J(n)=(bm−1bm−2...b1b0bm)2J((bmbm−1bm−2...b1b0)2)=(bm−1bm−2...b1b0bm)22진법 방식의 일반화를 위해 다음과 같이 정의하자.
- β0=β
- β1=γ
점화식은 다음과 같았다.
f(1)=α;f(2n)=2f(n)+β,forn≥1f(2n+1)=2f(n)+γ,forn≥1여기에 β0=β과 β1=γ를 적용하면 다음과 같이 된다.
f(1)=α;f(2n+0)=2f(n)+β0,forn≥1f(2n+1)=2f(n)+β1,forn≥1두번째와 세번째 점화식은 다음과 같이 하나로 합칠 수 있다.
f(2n+j)=2f(n)+βj,forj=0,1andn≥1이 점화식을 2진법으로 전개해 보면 다음과 같다.
f((bmbm−1...b1b0)2)=2f((bmbm−1...b3b2b1)2)+βb0=4f((bmbm−1...b3b2)2)+βb1+βb0=8f((bmbm−1...b3)2)+βb2+βb1+βb0...=2mf((bm)2)+2m−1βbm−1+...+2βb1+βb0=2mα+2m−1βbm−1+...+2βb1+βb0=(αβbm−1...βb1βb0)2α가 제일 앞에 있는 이유는, 제일 앞의 bm=1=α이기 때문이다.
그리고 한참 위에서 작성했던 표를 (새로운 관점으로) 다음과 같이 작성할 수 있다.
nf(n)1α22α+1β32α+1γ44α+2β+1β54α+2β+1γ64α+2γ+1β74α+2γ+1γ88α+4β+2β+1β98α+4β+2β+1γn=100=(1100100)2 인 경우를 생각해 보자.
- β0=β
- β1=γ
일단 위와 같이 2진법으로 표기된 0⇒β이고, 2진법으로 표기된 1⇒γ 이므로
요세푸스 값 α=1,β=−1,γ=1 을 적용해보면 다음과 같다.
α와 γ가 공통적으로 이진법 1
을 의미하고, β가 이진법 0
을 의미하므로,
이진법 n
을 십진법으로 바꿀 때 이진법 0
이 있는 곳에 β 값인 -1
을 곱해주면 된다.
어떻게 이 방법이 비트 순환과 똑같은 결과를 내는 것일까?
비트가 3개인 모든 경우를 살펴보자.
- 111 : 7인 경우
- 110 : 6인 경우
- 101 : 5인 경우
- 100 : 4인 경우
7인 경우
7
인 경우를 먼저 생각해보자.
7과 같이 비트가 1
만 있는 경우는 0
이 없으므로 빼는 숫자가 없어 값이 그대로 나온다.
비트 순환을 하나 마나 똑같은 결과이므로 비트 순환과 똑같다.
이는 7 외에도 3(112), 15(11112) 등등 2x−1 형태인 모든 숫자에 해당될 것이다.
6인 경우
이번에는 6
인 경우를 생각해보자.
- 110 에서 1 을 빼면 101 이 된다.
110
=>101
이 되었으므로 좌측 비트 순환과 똑같다.
5인 경우
이번에는 5
인 경우를 생각해보자.
- 101 에서 10 을 빼면 011 이 된다.
101
=>011
이 되었으므로 좌측 비트 순환과 똑같다.
4인 경우
이번에는 4
인 경우를 생각해보자.
100
에서 1 을 빼면 011 이 된다.- 011 에서 10 을 빼면
001
이 된다. 100
=>001
이 되었으므로 좌측 비트 순환과 똑같다.
일반화한 식을 좀 더 일반화해보자
위에서 알아낸 점화식은 다음과 같았다.
f(1)=α,f(2n+j)=2f(n)+βj,forj=0,1andn≥1이를 다음과 같이 좀 더 일반화해볼 수 있을 것이다.
f(j)=αj,for1≤j<d;f(dn+j)=cf(n)+βj,for0≤j<dandn≥1d
와 c
를 보면 알 수 있겠지만, n
은 d진법
이고, f(n)
은 c진법
으로 생각하는 쪽이 계산이 편리하다.
f(19) 계산 예제
이제서야 1장의 마지막 예제를 이해할 수 있을 것 같다.
1장의 마지막 예제는 다음과 같은 점화식을 통해 f(19)
를 계산하는 것이다.
- 19는
3의 배수 + 1
이니까, f(3n+1)=10f(n)−2를 사용해 시도해보면 될 것 같다.3n + 1
을 보면,d = 3
이다.10f(n) - 2
를 보면,c = 10
이다.- 그리고
19
는18 + 1
이니까 3진법으로201
이다.
따라서 다음과 같이 전개할 수 있다.
n=(201)3=19f(n)=(576−2)3=5⋅10276⋅10−2=500+760−2=1258위의 5
, 76
, -2
는 다음과 같이 얻어낸 것이다.
- f(2)=5.
- f(3n+0)=10f(n)+76 이므로, β0=76.
- f(3n+1)=10f(n)−2 이므로, β1=−2.