1. 程式人生 > >從斐波那契數列窺探動態規劃

從斐波那契數列窺探動態規劃

利用動態規劃求解斐波那契數列

public class Fibonacci 
{
	static int f[]=new int[100];
	static long startTime=0;
	public static void init()
	{
		for(int i=0;i<f.length;i++)
			f[i]=-1;
	}
	public static void main(String[] args)
	{
		init();
		
		startTime=System.currentTimeMillis();
		fibonacci(40);
		System.out.println("time:"+(System.currentTimeMillis()-startTime));
		
		fibonacci2(40);
		
		startTime=System.currentTimeMillis();
		System.out.println(fibonacci3(40));
		System.out.println("time:"+(System.currentTimeMillis()-startTime));
	}
	static int fibonacci(int i) //遞迴是一種自上而下的動態規劃。
	{
		if(i==0)
		{
			return 0;
		}
		else if(i==1)
		{
			return 1;
		}
		else 
		{
			return fibonacci(i-1)+fibonacci(i-2);
		}
	}
	static int fibonacci2(int n) //一般的動態規劃,就是這種自下而上的動態規劃
	{
		int[] array=new int[n+1];
		array[0]=0;
		array[1]=1;
		long startTime=System.currentTimeMillis();
		for(int i=2;i<n+1;i++){
			array[i]=array[i-1]+array[i-2];
		}
		for(int i=1;i<n+1;i++){
			System.out.print(array[i]+"  ");
		}
		System.out.println();
		System.out.println("time:"+(System.currentTimeMillis()-startTime));
		return array[40];
	}
	static int fibonacci3(int n)  //備忘錄法,跟自頂向下的動態規劃遞迴是一樣的,不同的是備忘錄法利用了一個數組來記錄每個子問題的解,從而避免重複求解,將問題簡化。
	{
			if(f[n]>=0)
				return f[n];
			if(n == 0)
			{
				f[0] = 0;
				return f[0];
			}
			if(n == 1)
			{
				f[1] = 1;
				return f[1];
			}
			f[n] = fibonacci3(n-1) + fibonacci3(n-2);
			return f[n];
	}
}
結果如下:

time:545
1  1  2  3  5  8  13  21  34  55  89  144  233  377  610  987  1597  2584  4181  6765  10946  17711  28657  46368  75025  121393  196418  317811  514229  832040  1346269  2178309  3524578  5702887  9227465  14930352  24157817  39088169  63245986  102334155  
time:0
102334155
time:0

相比較:備忘錄法和自下向上的動態規劃效率差不多,而自頂向下的遞迴則效率很慢。是以空間換時間的做法。

動態規劃分為三種:自上而下有兩種,備忘錄法和遞迴。自下而上有一種,就是一般我們所使用的。

而備忘錄和遞迴不同,備忘錄法利用了一個額外陣列來儲存,計算過程中子問題的解,從而避免了遞迴方法中重複求解子問題的問題。

除了以上幾種方法外還有求通項公式的方法直接得出F(n)=(1/√5)*{[(1+√5)/2]^n - [(1-√5)/2]^n}。求解更快速,但這是利用數學的方法,程式設計時不支援這樣做。

結論:

動態規劃求解的問題的一般要具有3個性質:

(1) 最優化原理:如果問題的最優解所包含的子問題的解也是最優的,就稱該問題具有最優子結構,即滿足最優化原理。

(2) 無後效性:即某階段狀態一旦確定,就不受這個狀態以後決策的影響。也就是說,某狀態以後的過程不會影響以前的狀態,只與當前狀態有關。

(3) 有重疊子問題:即子問題之間是不獨立的,一個子問題在下一階段決策中可能被多次使用到。(該性質並不是動態規劃適用的必要條件,但是如果沒有這條性質,動態規劃演算法同其他演算法相比就不具備優勢