구체수학 01.재귀적인 문제들.연습문제
01.RECURRENT PROBLEMS.Exercises
- 이 문서는 (책) CONCRETE MATHEMATICS(구체수학)책의 1장 연습 문제 중 몇몇을 공부하며 메모한 것입니다.
Warmups
Homework exercises
1.8
문제
다음 점화식의 해를 구하라.
Q0=α;Q1=β;Qn=(1+Qn−1)1Qn−2,forn>1.Q0=α;Q1=β;Qn=(1+Qn−1)1Qn−2,forn>1.모든 n≥0n≥0에 대해 Qn≠0Qn≠0이라고 가정하라.
풀이
위의 점화식은 python 이라면 다음과 같을 것이다.
def Q(n):
if n == 0:
return alpha
if n == 1:
return beta
return (1 + Q(n-1)) / Q(n-2)
코딩 문제라면, 위의 재귀함수의 시간 복잡도를 최대한 개선하는 것이 목표라고 볼 수 있겠다.
일단 순서대로 풀어내 보자.
Q0=αQ1=βQ2=(1+Q1)1Q0=(1+β)1α=1+βαQ3=(1+Q2)1Q1=(1+(1+β)1α)1β=(αα+1α+βα)1β=α+β+1αβQ4=(1+Q3)1Q2=(1+α+β+1αβ)1(1+β)1α=(αβ+α+β+1αβ)α(1+β)=(αβ+α+β+1β)1(1+β)=((α+1)(β+1)β)1(1+β)=α+1βQ5=(1+Q4)1Q3=(1+α+1β)1α+β+1αβ=(1+α+1β)αβα+β+1=(β+α+1β)αβα+β+1=(β+α+1β)αβα+β+1=αQ6=(1+Q5)1Q4=(1+α)1α+1β=(1+α)βα+1=βQ0=αQ1=βQ2=(1+Q1)1Q0=(1+β)1α=1+βαQ3=(1+Q2)1Q1=(1+(1+β)1α)1β=(αα+1α+βα)1β=α+β+1αβQ4=(1+Q3)1Q2=(1+α+β+1αβ)1(1+β)1α=(αβ+α+β+1αβ)α(1+β)=(αβ+α+β+1β)1(1+β)=⎛⎝(α+1)(β+1)β⎞⎠1(1+β)=α+1βQ5=(1+Q4)1Q3=(1+α+1β)1α+β+1αβ=(1+α+1β)αβα+β+1=(β+α+1β)αβα+β+1=(β+α+1β)αβα+β+1=αQ6=(1+Q5)1Q4=(1+α)1α+1β=(1+α)βα+1=β표로 나타내면 다음과 같이 순환하고 있음을 알 수 있다.
곰곰히 살펴보면 순환 주기는 5
라는 것도 알 수 있다.
n | QnQn |
---|---|
0 | αα |
1 | ββ |
2 | 1+βα1+βα |
3 | α+β+1αβα+β+1αβ |
4 | α+1βα+1β |
5 | αα |
6 | ββ |
그렇다면 n
값이 4보다 크다면, 5로 나눈 나머지를 새로운 n
으로 삼아 계산하면 된다.
따라서 이 문제의 답은 위의 표가 된다고 할 수 있다.
코드로 표현한다면 어떨까?
python이라면 다음과 같이 표현할 수 있을 것이다.
def Q(n):
n = n % 5
if n == 0:
return alpha
if n == 1:
return beta
return (1 + Q(n-1)) / Q(n-2)
n
을 5로 나눈 나머지로 재할당하고 있기 때문에, n
에 아무리 큰 값이 들어온다 하더라도 최대 8번만 재귀한다.
만약 n = 4
인 경우 다음과 같은 호출이 일어나기 때문이다.
재할당을 할 수 없거나 하지 않기로 약속한 환경이라면 다음과 같이 if
를 하나 더 추가하여 한 번 더 재귀하는 것도 방법이겠다.
def Q(n):
if n == 0:
return alpha
if n == 1:
return beta
if n > 4:
return Q(n % 5)
return (1 + Q(n-1)) / Q(n-2)
물론 순환 주기가 5 밖에 안 되기 때문에 다음과 같이 if
문을 잔뜩 사용한 하드 코드도 하나의 방법이겠지만, 별로 바람직해 보이지는 않는다.
def Q(n):
n = n % 5
if n == 0:
return alpha
if n == 1:
return beta
if n == 2:
return (1+beta) / alpha
if n == 3:
return (alpha + beta + 1) / (alpha * beta)
if n == 4:
return (alpha + 1) / beta
그런데 만약 2 장에서 배우는 아이버슨의 관례와 3 장에서 배우는 mod
를 사용하면, 위의 if
문이 떡칠된 코드는 다음과 같은 식으로 표현이 가능하다. 코드와 굉장히 유사하게 표현할 수 있다는 점이 재미있다. 보이는 것만 똑같은 것이 아니라 코드와 의미도 똑같다.
참고사항
- 아이버슨의 관례 표기법
[ ]
안에 들어간 식이 참인 경우1
을 리턴하고, 그 외의 경우0
을 리턴한다.
mod
- 나머지를 구하는 연산이다.