01揹包,多重揹包,完全揹包 總結

2021-09-25 05:47:23 字數 3721 閱讀 2567

可以先看下這篇部落格理解下動態規劃的思想:初識動態規劃

寫在前面的:這篇部落格主要寫的是,乙個容量為v的揹包去裝n個物品能獲得的最優解的問題

問題簡述:現在有乙個揹包,它能容納的最大重量為v,問揹包所能帶走的最大價值是多少?

01揹包:有n個物品,每個物品的重量為w[i],每個物品的價值為h[i]。

[對於每個物品不可以取多次,最多只能取一次,之所以叫做01揹包,0表示不取,1表示取]

多重揹包:有n種物品,每個物品的重量為w[i],每個物品的價值為h[i],每種物品有c[i]個。

完全揹包:有n種物品,每個物品的重量為w[i],每個物品的價值為h[i],每種物品有無限個。

設dp[i][j]表示處理到第i件物品時,容量為j的揹包能獲得的最大價值,處理結束後dp[n][v]就是我們所要求解的值。揹包問題第一層迴圈都是跑的物品總類數(目前我遇到的都是這樣子),一類一類地處理n類物品。當我們處理到第i件物品時,我們知道前i-1件物品在揹包容量為1、2、3、、、n時能獲得的最大價值分別是dp[i-1][1]、dp[i-1][2]、dp[i-1][3]、、、dp[i-1][v]。既然是01揹包,我們對第i件物品就有兩種策略:不取——那就好辦了,容量為j的揹包所能裝的價值在i-1的基礎上不變,就是dp[i-1][j];取——容量為j的揹包就得騰出w[i]的空位放物品i,此時的價值就為dp[i-1][j-w[i]]+h[i],所以dp[i][j]的最優解就是在這兩種情況之間,dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+h[i])。就這樣,跑完第二層迴圈我們就可以得到dp[i][j]的值(j=1、2、3、、、v)。

注意:我們對第i件物品的處理都是基於前i-1件物品的存放結果的,而前i-1件物品的存放結果第i件物品沒有參與,這也是01揹包問題一維優化的關鍵點。

—其實跑完了之後我們會發現,我們可以得到揹包容量在1~v範圍內的時去裝這n件物品能獲得的最大價值。

—後面的都是根據這個衍生出來的,而且後面完全揹包和多重揹包問題都能轉化成01揹包。

—揹包中有時可以看到乙個小優化,就是w[i]≤

\leq

≤w[j]&&h[i]≥

\geq

≥h[j]是可以直接把j物品去掉,但不常用,(我沒用過/哭笑),因為它不能優化最壞情況的複雜度。

**:

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(j=w[i]

; j<=v; j++

)//二維陣列這裡從w[i]到v,或者從v到w[i]沒有區別

dp[i]

[j]=

max(dp[i-1]

[j],dp[i-1]

[j-w[i]

]+h[i]

);

處理完第i件物品時,dp[j]就表示用容量為j的揹包去裝前i件物品能獲得的最大價值

基於上面說的二維的解法,既然處理第i件物品只與上一層(i-1)有關,那麼我們就可以將二維陣列轉化為一維陣列,轉化的過程中需要考慮乙個問題:怎樣才能保證我們得到的結果的組成中,每件物品只參與了一次。

因為我們還是要處理n件物品,所以第一層迴圈不變(總不可能說物品處理的順序會影響結果吧),然後看第二層迴圈,我們還是要通過第二層迴圈得到dp[i][j]的值(j=1、2、3、、、v),所以我們還是要遍歷w[i]到v,只不過這裡必須從v開始處理到w[i],因為我們處理dp[j]時會用到dp[j-w[i]]的值,而這個

dp[j-w[i]]必須是前i-1件物品參與的結果,不能有第i件物品的參與。如果我們從前往後處理,先處理dp[j-w[i]],在處理dp[j]的時候,構成dp[j-w[i]]最優解的可能也有第i件物品的參與,這樣的話我們就不能保證每件物品值參與了一次。

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(j=v; j>=w[i]

; j--

) dp[j]

=max

(dp[j]

,dp[j-w[i]

]+h[i]

);

dp[j]的意義和前面一樣,只不過每件物品能取無窮多次

解法:

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(j=w[i]

; j<=v; j++

) dp[j]

=max

(dp[j]

,dp[j-w[i]

]+h[i]

);

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(int k=

1; k<=v/w[i]

; k++

)for

(j=v; j>=w[i]

; j--

) dp[j]

=max

(dp[j]

,dp[j-w[i]

]+h[i]

);

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(int k=

1; k*w[i]

<=v; k<<=1)

for(j=v; j>=w[i]

; j--

) dp[j]

=max

(dp[j]

,dp[j-k*w[i]

]+k*h[i]

);

dp[j]的意義還是和前面一樣,每件物品能取有限次

解法:

memset

(dp,0,

sizeof

(dp));

for(i=

1; i<=n; i++

)for

(int k=

1; k<=c[i]

; k++

)for

(j=v; j>=w[i]

; j--

) dp[j]

=max

(dp[j]

,dp[j-w[i]

]+h[i]

);

for

(int i=

1; i<=n; i++)if

(c[i]

)for

(int j=v; j>=c[i]

*w[i]

; j--

) dp[j]

=max

(dp[j]

,dp[j-c[i]

*w[i]

]+c[i]

*h[i]);

}

加在後面的:對每一道動態規劃題目都思考其方程的意義以及如何得來,加深對動態規劃的理解

揹包 01揹包,完全揹包,多重揹包

哈哈 01揹包 f i v max 完全揹包 f i v max 多重揹包 f i v max include include include include include define maxn 1000 using namespace std int n,cap int w maxn 重量 花...

01揹包 完全揹包 多重揹包

01揹包 zeroonepack 有n件物品和乙個容量為v的揹包,每種物品均只有一件。第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。include include includeusing namespace std const int n 1000 10 int ...

01揹包 完全揹包 多重揹包

01揹包 zeroonepack 有n件物品和乙個容量為v的揹包。每種物品均只有一件 第i件物品的費用是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。完全揹包 completepack 有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。第i種物品的費用是c i 價值是w i 求...