1. 程式人生 > >動態規劃(演算法+理論) ★最短路徑

動態規劃(演算法+理論) ★最短路徑

首先介紹動態規劃的概念:
①問題是由交疊的自問題構成的,是對給定問題求解的遞推關係中的相同型別的*更小子問題的解*dp+回溯
②從頂至下,避免計算不需要計算的小解(記憶)
③求解最優化問題可以用動態規劃
動態規劃下筆寫程式碼前先去頂遞推式
直接看例項:
一、幣值最大化問題
給定一排n個硬幣,其面值均為正整數c1,c2,c3……cn,這些整數並不一定兩兩不同,請問如何選擇硬幣,使得在其原始位置互不相鄰的條件下,所選金額最大。

上述最大金額可用fn來表示,為了得到fn的遞推關係,將所有可行的選擇分為兩組,包括最後一枚硬幣和不包括最後一枚硬幣的。

F(N)={① 包括最後一枚硬幣 cn+f(n-2)
②不包括最後一枚硬幣 f(n-1)
其遞推式:
**則 fn=max{cn+f(n-2),f(n-1)}
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{c[i]+f[i-2],f[i-1]};
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

changemaking(D[1...m],n)
//應用dp求解,找出使硬幣加起來等於n時所需最少的硬幣數目
//其中幣值為d1<d2<d3<.......<dm,d1=1
//輸入:正整數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個物品能否放進去

{ 不行則考慮 F(i-1,j)
行則考慮 max{F(i-1,j),F(i-1,j-weight[i])+value[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{F(i-1,j),F(i-1,j-weight[i])+value[i]}

應用:最優二叉查詢樹
上
下