[Recursive] Recursive Algorithm(2)

조합의 수 계산

문제 : n개의 서로 다른 원소에서 m개를 선택하는 경우의 수

고등학교 수학시간에 배웠던 방법을 생각하면 다음과 같이 쉽게 풀어낼 수 있다.

from math import factorial as f

def combi(n,m):
	return f(n)/(f(m)*f(n-m))

재귀적 방법으로 생각하려면 특정한 하나의 원소 입장에서 볼 때, 그 원소를 포함하는 경우와 그렇지 않은 경우를 따로 계산해서 더하면 된다.

def combi(n,m):
	return combi(n-1,m) + combi(n-1,m-1)

이렇게 쓰면 될 것 같지만 trivial case가 빠져있다.

def combi(n,m):
	 if n == m:
	 	return 1
	 elif m == 0:
	 	return 1
	 else:
	 	return combi(n-1,m) + combi(n-1, m-1)

다음과 같이 써야한다.

이번에는 효율성 측면에서 생각해보자. m과 n이 커지면 함수의 호출이 수 없이 이루어진다. 오히려 loop를 이용하는 것이 훨씬 효율적일 것이다.

예를 들어 Recursive Algorithm(1)에서 만들었던 Fibonacci 순열을 생각해보면

fibo(4)에 대한 해답을 구할 때

fibo(4) #1 = fibo(3) #2 + fibo(2) #3
        = fibo(2) #4 + fibo(1) + fibo(1) + fibo(0)
        = fibo(1) #5 + fibo(0) #6 + fibo(1) #7 + fibo(1) #8 + fibo(0) #9

도합 9번의 함수가 호출되는 것을 알 수 있다.

그렇다면 실행시간에는 어떻게 차이가 있는지 recursive version과 iterative version을 비교해보자.

import time

def rec(n):
	if n <= 1:
		return n
	else:
		return rec(n-1) + rec(n-2)
		
def iter(n):
	if n <= 1:
		return n
	else:
		i = 2
		t0 = 0
		t1 = 1
		while i <= n:
			t0, t1 = t1, t0 + t1
			i += 1
		return t1
		
while True:
	nbr = int(input("Enter a number: "))
	if nbr == -1:
		break
m     ,	
	ts = time.time()
	fibo = iter(nbr)
	ts = time.time() - ts
	print("Iterative version: %d (%.3f)" % (fibo, ts))
	ts = time.time()
	fibo = rec(nbr)
	ts = time.time() - ts
	print("Recursive version %d (%.3f)" % (fibo, ts))

실행화면

Enter a number : 20
Iterative version : 6765 (0.000)
Recursive version : 6765 (0.003)

Enter a number : 30
Iterative version : 832040 (0.000)
Recursive version : 832040 (0.376)

Enter a number : 35
Iterative version : 9227465 (0.000)
Recursive version : 9227465 (4.166)

Comments