スポンサーリンク

再帰を使った場合

参考:[c言語]ナップザック問題を動的計画法でコーディング

下記がサンプルコードになります。
f(n)からf(n-1)とf(n-2)を再帰的に呼び出します。
重複計算もあって、n=45で13秒かかっています。

$ cat sample.c 
#include <stdio.h>
#include <time.h>

//n >= 0
int getFibNum(int n){
	if(n <= 1){
		return n;
	}
	return getFibNum(n - 1) + getFibNum(n - 2);
}

int main(){
	time_t startTime;
	
	printf("%d\n", getFibNum(1));
	printf("%d\n", getFibNum(2));
	printf("%d\n", getFibNum(6));
	printf("%d\n", getFibNum(9));
	
	startTime = time(NULL);
	printf("%d\n", getFibNum(45));
	printf("%ldsec", time(NULL) - startTime);
	
	return 0;
}

下記が実行結果になります。
$ gcc -o sample sample.c
$ ./sample 
1
1
8
34
1134903170
13sec

スポンサーリンク

動的計画法のメモ化再帰を使った場合

重複計算を避け、一度計算したら結果を記憶させておき、計算結果を再利用していきます。
0で初期化した配列を定義しておき、計算されていれば(配列の要素が!0なら)再利用し、
計算されていなければ(配列の要素が0なら)計算していきます。
n=45で1秒以下で収まりました(time関数なので精度は秒単位です)。

下記がサンプルコードになります。

$ cat sample1.c 
#include <stdio.h>
#include <time.h>

int data[100] = {};
//n >= 1
int getFibNum(int n){
	if(n <= 1){
		return n;
	}
	if(data[n]){
		return data[n];
	}else{
		data[n] = getFibNum(n - 1) + getFibNum(n - 2);
		return data[n];
	}
}

int main(){
	time_t startTime;
	
	printf("%d\n", getFibNum(1));
	printf("%d\n", getFibNum(2));
	printf("%d\n", getFibNum(6));
	printf("%d\n", getFibNum(9));
	
	startTime = time(NULL);
	printf("%d\n", getFibNum(45));
	printf("%ldsec", time(NULL) - startTime);
	
	return 0;
}

下記が実行結果になります。
$ gcc -o sample sample1.c
$ ./sample 
1
1
8
34
1134903170
0sec

動的計画法で漸化式を使った場合

漸化式を使って、n=0, 1, 2, 3.......と、順にループ処理をして計算していきます。
数学的な思考になれていると、こちらの方が自然な方法に感じるかもしれません。
再帰処理のように重複計算もないので、計算量も削減できます。

$ cat sample2.c 
#include <stdio.h>
#include <time.h>

//n >= 1
int getFibNum(int n){
	int An,  An_1, An_2;
	int i;

	if(n <= 1){
		return n;
	}
	
	An_1 = 1;
	An_2 = 0;
	
	for(i = 2; i <= n; i++){
		An = An_1 +  An_2;
		An_2 = An_1;
		An_1 = An;
	}
	
	return An;
}

int main(){
	time_t startTime;
	
	printf("%d\n", getFibNum(1));
	printf("%d\n", getFibNum(2));
	printf("%d\n", getFibNum(6));
	printf("%d\n", getFibNum(9));
	
	startTime = time(NULL);
	printf("%d\n", getFibNum(45));
	printf("%ldsec", time(NULL) - startTime);
	
	return 0;
}

下記が実行結果になります。
$ gcc -o sample sample2.c
$ ./sample 
1
1
8
34
1134903170
0sec

スポンサーリンク