递归讨论(二)续
在討論二中,展示了鋼條分段的方法,只不過解題的方法采用的是自頂而下的策略。
個人理解的自頂而下的策略:
首先我們不知道一個大問題的答案,但我們可以將問題規模縮小,外加上已知的一部分。進而變成求解這個小規模問題答案的過程,利用遞歸原理,層層向下,最終回到一個最簡單的問題。
這種處理問題的方式,難免會有重復求解的情況出現。上篇中也有提到!!!
先還是把上篇的部分代碼搞過來看看。
int get_max(int* price,int* len,int num,int *p)//新增的這個指針p指向一個記錄數組,下標為長度num-1,我們用來記錄對應長度num下的最大收益 {int result=0;if(num>=1&&p[num-1]>=0) //此處判斷就起到從記錄表中查值作用。return p[num-1];if(num == 0)//由標記A處的num-len[i]以及其上的if判斷,可以看出下次調用get_max時,可能出現num為0的情況return 0;for(int i=1;i<=6;i++){if(num >=len[ i-1]){result = std::max(result,get_max(price,len,num-len[i-1],p)+price[i-1]);//標記A處 }}p[num-1] = result;return result; }?
從代碼中,我們可以粗略計算下,總共調用了多少次get_max();首先在不斷的調用中,get_max()函數中的num值取遍了0-num,權且計作num次
在每次調用中,我們都需要for()循環下,(因為粗略計算嘛)我們就不考慮其中的if判斷了。
最終我們計算出的調用次數:num*6,很類似雙層循環啊
看num值從0變化到num的最大值
價格從1到6變化,嵌套在num的每次變化,顯然是雙層循環了。
我們再分析下:
上述程序中,每次調用的get(..num..),都為了計算當前num的最大收益的吧。只不過大的num根據小的num計算出來,通過遞歸調用實現,但按照程序的實際運行的順序來說,最終還是小num的最大收益先被計算出,然后返回給大的num的使用。這是一種從頂向下,然后結果再層層上返回的過程。
與其這么麻煩,我們不如先計算小num,然后將小num的值貢獻給比它大的num,這樣就減少了遞歸那樣不斷的調用了。(自下而上的策略)
這樣做的要求就是:我們必須保證num從1到最大時,每個循環都獲得當前num下的最大的收益,先上代碼好了:
void get_max(int* len,int* price,int n,int num,int *p,int* s)//其中n表示可分段種類數 num為鋼條長度,p記錄的當前num下首次截斷的長度,下標為num,s記錄的當前num下最大收益 {s[0] = 0;for(int i=1;i<=num;i++){int q = 0;//當前num下,q用于第二層循環的最大收益的記錄for(int j=0;j<n;j++){if(i>=len[j]){s[i] = s[i-len[j]]+price[j];}if(s[i] > q)//當條件成立時,說明當前num下,最大收益的組合被更新了哦{q = s[i]; p[i]=j;}}s[i] = q;} }這樣我們就獲得最大收益,同時也可以獲得如何分段的方法。
同時一定程度也減少了程序的復雜性。
如果下次再碰到動態規劃問題,就想想這個!理解比較淺薄,望指教!
轉載于:https://www.cnblogs.com/qinghua0310/p/4062935.html
總結
- 上一篇: 全球隔夜主要金融市场回顾
- 下一篇: log4j的NDC/MDC区别与应用