演算法學習筆記4 動態規劃 揹包問題

2021-08-08 02:09:04 字數 3077 閱讀 3297

其實動態規劃特別抽象,特別難講。這裡也可以參考一篇博文,用講故事的方式講了出來。

通過金礦模型介紹動態規劃

我的理解就是「用更多的問題來回答問題」。

動態規劃是一種求解最優化問題的方法,因為它沒有乙個確定的數學表示式,或者是明確的解題步驟,說起來會比較抽象,我們只能在實際題目中體會。首先說幾個概念吧:

這裡先給個栗子:

給定乙個整數序列,求這個序列的最長上公升子串行,子串行可以是不連續的。比如對於序列(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比較 ...