參考文獻 《演算法導論》 第15章
所謂“動態規劃“”,就是尋求最優解的過程,採用的也是遞迴的思想,不過與分而治之的區別是:分治法,每個子問題是獨立的,只要求出每個字問題,然後合并一下,就可以了;而動態規劃雖然也是遞迴的過程,但子問題不獨立,下文將結合例子講解。
根據《演算法導論》,動態規劃(dynamic programming) 包括一下四個方面:
1,描述最優解的結構
2,遞迴定義最優解的值
3,自底向上的方式計算最優解的值
4,有計算出的結果構造一個最優解。
還是引用書上的裝配調度來分析。不清楚題目的,請看原始第二版 P192
為了 找到最優路徑,如果我們採用笨辦法就是所有路徑都算一遍,當然肯定可以的,但是複雜度為O(2^n),電腦沒法接受。
在此背景下,動態規劃來了。
動態規劃的核心思想是:子問題最優,子子問題最優,不斷最優。而在最優的過程中,充分利用了,子問題之間的關係,避免重複計算。後一個最優一定是在前一個最優的基礎上建立的,而分治沒有。根本原因,在於,動態規劃針對的就是最優問題。當然分治法也可以針對最優,但是動態規劃在求最優方面是分治的進化,是更進階的東西。
據上面的例子:
假如分治法找到到a1,3的最短路徑,OK,所有遍曆:
e1 a1,1 a1,2 a1,3
e 1 a1,1 a2,2 a1,3
e2 a2,1 a2,2 a1,3
e2 a2,1 a1,2 a1,3
假設採用動態規劃:
通向a1,3有倆條路徑,a1,2 和 a2,2
此時,分別計算通往a1,2 a2,2 的最優路徑,然後比較,再決定哪條路徑最優。
在此過程中,a1,2 到 a1,3隻計算一次,而在,分治法中,a1,2 到a1,3計算了倆次,如上第一行和第四行,依此原理其他路徑也只要計算一次;這樣計算量大大縮減,當然有的人會說,每個點增加了一次比較(選擇子最優)。
但是點到點之間的重複計算隨著規模的增大而增大。也正由於比較的存在,一個點一次,導致最後的複雜度為O(N)。
根據《演算法導論》給出遞推關係式:
下面嘗試給出代碼:
我自己用遞迴函式寫的代碼
#include<iostream>using namespace std;//聲明幾個全域變數。一般不建議聲明全域變數,但這隻是功能測試。int a1[6]={7,9,3,4,8,4};int a2[6]={8,5,6,4,5,7};int t1[5]={2,3,1,3,4};int t2[5]={2,1,2,2,1};int e1=2;//進入網站的時間int e2=4;int x1=3;//退出網站的時間int x2=2;int l1[5];int l2[5];//記錄留個位置 int sum1;int sum2;//f1 路線1上到網站_a1的最優路徑的時間總和,_t1路徑轉移數組的下標,其餘類似void fastWay(int f1,int f2,int _t1,int _a1,int _t2,int _a2){ if(_t1>=5||_t2>=5|| _a1>=6|| _a2>=6) return;//遍曆完成int tmp1;int tmp2;tmp1=f2+t2[_t2]+a1[_a1];tmp2=f1+a1[_a1];int inputData1,inputData2; if(tmp1>tmp2){ l1[_a1-1]=1;inputData1=tmp2; }else{ l1[_a1-1]=2;inputData1=tmp1;}sum1=inputData1;tmp1=f1+t1[_t1]+a2[_a2];tmp2=f2+a2[_a2];if(tmp1>tmp2){l2[_a2-1]=2;inputData2=tmp2;}else{l2[_a2-1]=1;inputData2=tmp1;}sum2=inputData2;_t1++;_a1++;_t2++;_a2++;fastWay(inputData1,inputData2,_t1,_a1,_t2,_a2);}int main(){ int addedF1=e1+a1[0]; int addedF2=e2+a2[0]; fastWay(addedF1,addedF2,0,1,0,1); for(int i=0;i<5;++i) cout<<l1[i]; cout<<endl; for(int i=0;i<5;++i) cout<<l2[i]; if(sum1+x1>sum2+x2) {cout<<"花的最少時間是:"<<sum2+x2<<"經過的網站為:"; for(int i=0;i<5;++i) cout<<l2[i];cout<<2; } else { cout<<"花的最少時間是:"<<sum1+x1<<"經過的網站為:"; for(int i=0;i<5;++i) cout<<l1[i];cout<<1; } return 0;}
測試結果:
程式利用了函數的遞迴,需要反覆壓入棧,效率,不如直接迴圈高,如 http://www.cnblogs.com/Anker/archive/2013/03/09/2951785.html 寫的代碼 還是不錯的。