動態規劃與分治方法相似,均是通過子問題的解求解原問題。區別是分治演算法在求解子問題時會做許多不必要的工作,它會反覆求解那些公共子問題;而動態規劃演算法對每個子子問題都只求解一次,將其解儲存在乙個**中,從而無需每次求解子子問題時都重新計算,避免了不必要的計算工作。
鋼條切割問題:給定一段長度為n英吋的鋼條和乙個**表pi(i=1,2,...n),求切割鋼條方案,使得銷售收益rn最大。
長度i123
4567
8910**pi15
891017
1720
2430
先說一下整體的求解方法:將鋼條從左邊切割下長度為i的一段,只對右邊剩下的長度為n-i的一段繼續進行切割,對左邊的一段則不再進行切割。我們可以用公式來描述上述方法
rn=max(pi+rn-i) 1<=i<=n
首先用分治的思想求解最優鋼條切割問題
這是一種直接的自頂向下的遞迴方法,這種方法效率極低,因為cut-rod反覆地求解相同的子問題。通過圖例來說明此問題:
圖中,從父節點s到子節點t的邊表示從鋼條左端切下長度為s-t的一段,然後繼續遞迴求解剩餘的規模為t的子問題。可以看出,在圖中有許多相同的子樹,比如以1、2為根的子樹,在利用前面的演算法求解時,每次都要對相同的子問題多次求解,導致效率很低。
使用動態規劃方法求解最優鋼條切割問題
前面的演算法最大的問題就是反覆求解相同的子問題,而動態規劃方法通過安排求解順序,做到對每個子問題只求解一次,並將結果儲存下來。以後再次需要此子問題的解時,只需查詢儲存的結果(通過空間換取時間)。
帶備忘的自頂向下法
memoized-cut-rod(p,n)
for i=0 to n
r[i]=-1
return memoized-cut-aux(p,n,r)
memoized-cut-rod-aux(p,n,r)
if r[n]>=0
return r[n]
if n==0
q=0else q=-10000
for i=1 to n
q=max(q,p[i]+memoized-cut-rod-aux(p,n-i,r))
r[n]=q
return q
用c++實現如下:
int cut_rod_aux(vectorp, int n, vectorr)
r[n] = q;
return q;
}int cur_rod(vectorp, int n)
int main()
; int max = cur_rod(v, 9);
cout << max << endl;
system("pause");
return 0;
}
帶備忘的遞迴演算法為每個子問題維護乙個表項來儲存它的解。每個表項的初值設為乙個特殊值,表示尚未填入子問題的解。當遞迴呼叫過程中第一次遇到子問題時,計算其解,並存入對應表項。隨後每次遇到同乙個子問題,只是簡單地查表,返回其解。
自底向上的動態規劃演算法
bottom-up-cut-rod(p,n)
r[0]=0
for j=1 to n //從小打大,
q=-1
for i=1 to j //i是切割點
q=max(q,p[i]+r[j-i]) //計算長度為j時的最大銷售收益
r[j]=q //儲存長度為j時的最大銷售收益
return r[n] //返回長度為n時的最大銷售收益
上述方法需要恰當定義子問題「規模」的概念,使得任何子問題的求解都只依賴於更小的子問題的求解。所以通過將子問題按規模排序,按從小到大的順序進行求解。當求解某個子問題時,它所依賴的那些更小的子問題都已經求解完畢,結果已經儲存。這樣,每個子問題只需求解一次,當求解乙個子問題時,它的所有前提子問題都已求解完成。
求解規模為j的子問題的方法與cut-rod所採用的方法相同,只是通過乙個陣列將r[j]的元素儲存下來,直接訪問r[j-i]來獲得規模為j-i的子問題的解,而不必進行遞迴呼叫。
擴充的動態規劃演算法(可以計算出切割後的鋼條的長度)
extended-bottom-up-cut-rod(p,n)
r[0]=0
for j=1 to n
q=-1
for i=1 to j
if q
print-cut-rod-solution(p,n)
(r,s)=extended-bottom-up-cut-rod
while n>0
print s[n]
n=n-s[n]
extended-bottom-up-cut-rod(p,n)演算法是在bottom-up-cut-rod上的略微改進,新建立陣列s,在求解規模為j的子問題時將第一段鋼條的最優切割長度i儲存在s[j]中。
print-cut-rod-solution(p,n)演算法通過呼叫
extended-bottom-up-cut-rod(p,n)來計算切割下來的每段鋼條的長度s[1...n],最後輸出長度為n的鋼條的完整的最優切割方案。
動態規劃演算法
一 動態規劃演算法原理 將待求解的問題分解成若干個相互聯絡的子問題,先求解子問題,然後從這些子問題的解得到原問題的解 對於重複出現的子問題,只在第一次遇到的時候對它進行求解,並把答案儲存起來。了不去求解相同的子問題,引入乙個陣列,把所有子問題的解存於該陣列中,這就是動態規劃所採用的基本方法。動態規劃...
動態規劃演算法
動態規劃 通過把原問題分解為相對簡單的子問題來求解複雜問題。動態規劃常常適用於有重疊子問題和最優子結構性質的問題。演算法總體思想 演算法的基本步驟 演算法的基本要素 最優子結構 重疊子問題 備忘錄方法 問題描述 子串行 公共子串行 最長公共子串行 lcs 問題 問題分析 動態規劃求解lcs問題 最長...
動態規劃演算法
動態規劃演算法的思路 動態規劃法即 dynamic programming method dp 是系統分析中的種常用方法。動態規劃法是20世紀50年代由貝爾曼 r.bellman 等人提出的,用來解決多階段決策過程問題的一種最優化方法。多階段決策過程是指把研究問題分成若干個相互聯絡的階段,由每個階段...