其實動態規劃特別抽象,特別難講。這裡也可以參考一篇博文,用講故事的方式講了出來。
通過金礦模型介紹動態規劃
我的理解就是「用更多的問題來回答問題」。
動態規劃是一種求解最優化問題的方法,因為它沒有乙個確定的數學表示式,或者是明確的解題步驟,說起來會比較抽象,我們只能在實際題目中體會。首先說幾個概念吧:
這裡先給個栗子:
給定乙個整數序列,求這個序列的最長上公升子串行,子串行可以是不連續的。比如對於序列(1,7,2,8,3,4),它的子串行是(1,2,3,4)。
1. 階段
動態規劃含有一種遞推的思想,如果乙個問題可以分成不同的「階段」,上乙個階段的決策直接影響下乙個階段,我們就可以考慮使用動態規劃,依次求出每乙個階段的最優解,直到解決整個問題,也就是拆分問題。
比如上面的例子,我們可以把問題拆解為求以k結尾的序列的最長子序列,也就是分別求序列的最長上公升子串行。
2. 狀態
每乙個階段的客觀條件我們稱為「狀態」。乙個階段可能有乙個或多個狀態,我們可以用乙個狀態變數來表示,比如上面每乙個階段可以表示為。
這裡我們可以看到,其實階段和狀態有時候是不區分的。
3. 決策(狀態轉移方程)
從乙個階段演變到下乙個階段,叫做「決策」,也就是說不同的決策可能會演變到不同的階段。
而狀態跟狀態之間的關係式,叫「狀態轉移方程」,其實它影響了我們的決策,比如上面的例子,在選擇數字1之後,下一步是選擇7還是選擇2,就需要決策,而如果我們的狀態轉移方程是f_i=min(a_i,a_i-1),那麼我們就會選擇較小的2。
這樣,每個階段作出決策,我們就能得到最終問題的解。
上面例子的具體**實現如下:
#include
#include
#include
using
namespace
std;
int main()
; for(int i=0;icout
<" ";
cout
>a[i];
for(int i=1;ifor(int j=0;jif(a[j]1);}}
cout
<1]<" ";
cout
delete dp;
return
0;}
下面給出幾個實際問題:
1.揹包問題
題目描述:
辰辰是個很有潛能、天資聰穎的孩子,他的夢想是稱為世界上最偉大的醫師。 為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。 醫師把他帶到個到處都是草藥的山洞裡對他說: 「孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。 我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是乙個聰明的孩子,你應該可以讓採到的草藥的總價值最大。」 如果你是辰辰,你能完成這個任務嗎?
輸入描述:
輸入的第一行有兩個整數t(1 <= t <= 1000)和m(1 <= m <= 100),t代表總共能夠用來採藥的時間,m代表山洞裡的草藥的數目。
接下來的m行每行包括兩個在1到100之間(包括1和100)的的整數,分別表示採摘某株草藥的時間和這株草藥的價值。
#coding = utf-8
#backpack problem/dynamic problem
while true:
try:
time,m=raw_input().split()
time=int(time)
m=int(m)
t=#time
v=#value
for i in xrange(m):
t1,t2=raw_input().split()
t1=int(t1)
t2=int(t2)
dp=[0
for i in range(time+1)]
for i in xrange(m):
for j in xrange(time,t[i]-1,-1):
dp[j]=max(dp[j],dp[j-t[i]]+v[i])
print dp[time]
except:
break
2.合唱團
題目描述:
有 n 個學生站成一排,每個學生有乙個能力值,牛牛想從這 n 個學生中按照順序選取 k 名學生,要求相鄰兩個學生的位置編號的差不超過 d,使得這 k 個學生的能力值的乘積最大,你能返回最大的乘積嗎?
輸入描述:
每個輸入包含 1 個測試用例。每個測試資料的第一行包含乙個整數 n (1 <= n <= 50),表示學生的個數,接下來的一行,包含 n 個整數,按順序表示每個學生的能力值 ai(-50 <= ai <= 50)。接下來的一行包含兩個整數,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
#coding=utf-8
n=input()
a=list(raw_input().split())
a=[int(i) for i in
a]ik,d=raw_input().split()
ik=int(ik)
d=int(d)
#動態規劃,用兩個陣列,保留一正一負兩個結果
mx=[[0
for i in range(n)] for i in range(ik)]
mn=[[0
for i in range(n)] for i in range(ik)]
m=0for i in range(n):
mx[0][i]=mn[0][i]=a[i]
for k in range(1,ik):
for j in range(i-1,-1,-1):
if i-j>d:
break
mx[k][i]=max(mx[k][i],max(mx[k-1][j]*a[i],mn[k-1][j]*a[i]))
mn[k][i]=min(mn[k][i],min(mx[k-1][j]*a[i],mn[k-1][j]*a[i]))
m=max(m,mx[ik-1][i])
print m
筆記 演算法學習 動態規劃 揹包問題總結(1)
1 0 1揹包 for i 1 to n do for j vtot downto v i do f j max f j v i w i f j 如果題目要求恰好裝滿揹包,則f陣列除了f 0 初始化為0之外,其他的初始化為 maxlongint 2 完全揹包 每個物品有無限件可用 for i 1 t...
演算法 4 動態規劃揹包
容量 m kg 的揹包,另外有 i個物品,重量分別為 w 1 w 2 w i kg 價值分別為 p 1 p 2 p i 元 將哪些物品放入揹包可以使得揹包的總價值最大?最大價值是多少?我們要求得 i個物體放入容量為 m kg 的揹包的最大價值 記為 c i m 在選擇物品的時候,對於每種物品 i只有...
動態規劃4揹包問題
貪心演算法。1 先放入價值最大的。這個肯定不行 2 放入平均價值最大的,也不行 二維陣列作為記憶化搜尋 第一行,只有0這個物品的時候,對應容量的最大值 第二行,考慮0和1兩件物品的時候 第三行,0,1,2都考慮 1,2 這個點 對1考慮放入1,對0考慮容量為0的時候,對應的大小。兩個加起來和6比較 ...