1. 程式人生 > 其它 >斐波那契數列切入動態規劃

斐波那契數列切入動態規劃

斐波那契數列切入動態規劃

動態規劃指儲存已出現過的值。

1.普通遞迴

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

2.備忘錄法

#include<bits/stdc++.h>
using namespace std ;
int fib(int n,int Memo[]);
int Fibonacci(int n)
{
		if(n<=0)
			return n;
		int Memo[n+1];		
		for(int i=0;i<=n;i++)
			Memo[i]=-1;
		return fib(n, Memo);
	}
int fib(int n,int Memo[])
{
		
		if(Memo[n]!=-1)
			return Memo[n];
	//如果已經求出了fib(n)的值直接返回,否則將求出的值儲存在Memo備忘錄中。				
		if(n<=2)
			Memo[n]=1;
		
		else Memo[n]=fib( n-1,Memo)+fib(n-2,Memo);	
		
		return Memo[n];
}

int main(){
   cout<<Fibonacci(12)<<endl;
   return 0;
}

以上兩種方法都是自頂向下的由求父值轉向求子值的遞迴思想;

於是演變出第三種思想,先求小運算元;

3.自下至上的動態規劃

int Fibonacci(int n){
    int memo[n+1];
    memo[0]=0;
    memo[1]=1;
    for(int i=2;i<=n;i++){
        memo[i]=memo[i-1]+memo[i-2];
    }
    return memo[n];
}

既然 我們要求fib(n),我們就把所有運算元儲存在一個數組中,依次正向推進得到結果,遞迴是反相推演。

進一步推演,每次參與計算只需有規律推進的三個運算元。

int Fibonacci(int n){
    
    int memo_0=0;
    int memo_1=1;
    int memo_n;
    for(int i=2;i<=n;i++){
       memo_n=memo_0+memo_1;
       memo_0=memo_1;
       memo_1=memo_n;
    }
    return memo_n;
}

這三個運算元是有規律依次遞進的,所以可以節省陣列的空間。感覺像是連結串列指標。