首先介紹動態規劃的概念:
①問題是由交疊的自問題構成的,是對給定問題求解的遞推關係中的相同型別的*更小子問題的解*dp+回溯
②從頂至下,避免計算不需要計算的小解(記憶)
③求解最優化問題可以用動態規劃
動態規劃下筆寫**前先去頂遞推式
直接看例項:
一、幣值最大化問題
給定一排n個硬幣,其面值均為正整數c1,c2,c3……cn,這些整數並不一定兩兩不同,請問如何選擇硬幣,使得在其原始位置互不相鄰的條件下,所選金額最大。
上述最大金額可用fn來表示,為了得到fn的遞推關係,將所有可行的選擇分為兩組,包括最後一枚硬幣和不包括最後一枚硬幣的。
f(n)=
f(0)=0,f(1)=c1**
coinrow(c[1..n])
//應用上述遞推式,自底向上求最大金額
//在滿足所選硬幣不相鄰的條件下,從一排硬幣中選擇最大金額的硬幣
//輸入:陣列c儲存n個硬幣的面值,下標從1開始
//輸出:可選硬幣的最大金額
f[0]=0;
f[1]=c[1];
for(i=2;i<=n;++i)
f[i]=max;
return f[n];
可用上述演算法來求解一排硬幣5 1 2 10 6 2,其最大金額為17
求出最大值後利用回溯計算過程來確定構成最大金額的硬幣元素。
在最後一次引用遞推方程時,是c6+f(4)給出了最大金額17.這意味著c6是最優解的一部分,繼續回溯f(4)的計算,最大金額由c4+f(2)給出,這意味著c4也是最優解的一部分,最後計算f(2)的時候,其最大值由f(1)產生,這意味著c2不是最優解的一部分,而c1是。故得出結論 c1 ,c4,c6
該過程顯然耗費了o(n)的時間和空間。遠遠優於利用遞推方程自頂向下遞推求解或者窮舉查詢。
二、找零問題
需找零金額為n,最少要用多少面值為d1
change******(d[1...m],n)
//應用dp求解,找出使硬幣加起來等於n時所需最少的硬幣數目
//其中幣值為d1//輸入:正整數n以及用於表示幣值的遞增整數陣列d[1..m],d[1]=1
//輸出:總金額等於n的硬幣最少的數目
f[0]=0;
for(i=1;i<=n;++i)
temp=max;
j=1;
while( j<=m&&i>=d[i])
temp=min(f[i-d[j]],temp);
j=j+1;
f[i]=temp+1;
return f(n);
則對於n=6,幣值為1,3,4的硬幣應用上述演算法產生的結果是2,回溯之後硬幣集合為2個3
**總結:
1找出遞推關係
2從底向上
3令f(0)=0
4每步選最優步**
應用:揹包問題
記憶法:將自頂向下和自底向上的方法結合起來
★對必要的自問題只求解一次
思路:
對於i個物品,承重量為j的揹包的最優子集,自頂向下則考慮第i個物品能否放進去
不放第i個物品和放第i個物品
初始條件: f(i,0)=0,f(0,j)=0
對上述遞推式的解釋:可以把前i個物品中能夠放進承重量為j的揹包中的子集分成兩個類別,包括第i個物品的子集和不包括第i個物品的子集,則有:
(1)根據定義,在不包括第i個物品的子集中,最優子集的價值為f(i-1,j)
(2)在包括第i個物品的子集中,(j-wi>=0)最優子集是由該物品和前i-1個物品中能夠放進承重量為j-wi的揹包的最優子集組成,此時最優子集的價值為max
應用:最優二叉查詢樹
動態規劃演算法理解
幾個月前已經弄懂了的演算法,現在回憶起來這麼費勁。又得重頭開始,真是浪費生命啊。再好的腦袋也不如爛筆頭!這裡用最長公共子串行問題 lcs 來說明演算法 給定兩個序列 x y 求x y長度最長的公共子串行。前期儲備知識 公共子串行不等於公共字串 注意區分 例如,如果x y 那麼就是x和y的公共子串行,...
動態規劃演算法 理解
動態規劃 多階段 兩段 最優化決策解決問題的過程就稱為動態規劃。1 描述優解的結構特徵。2 遞迴地定義乙個最優解的值。3 自底向上計算乙個最優解的值。4 從已計算的資訊中構造乙個最優解。1 最優化原理 問題的最優解包含的字問題也有最優解,就稱該問題具有最優子結構,滿足最優化原理。單調遞增最長子序列 ...
動態規劃演算法
一 動態規劃演算法原理 將待求解的問題分解成若干個相互聯絡的子問題,先求解子問題,然後從這些子問題的解得到原問題的解 對於重複出現的子問題,只在第一次遇到的時候對它進行求解,並把答案儲存起來。了不去求解相同的子問題,引入乙個陣列,把所有子問題的解存於該陣列中,這就是動態規劃所採用的基本方法。動態規劃...