弈星面板延期上線,60點券給艾琳,五款新面板月中上線
阿新 • • 發佈:2022-04-05
服了,揹包問題我真的是學了就忘學了就忘學了就忘……
寫個部落格總結一下,加深加深印象(供以後忘了的時候參考)。
問題描述:
有N件物品和一個容量為V的揹包。第i件物品的體積是w[i],價值是v[i]。求解將哪些物品裝入揹包可使價值總和最大。
問題特點:
每種物品只有一件,有兩個狀態,選擇放或者不放。
狀態轉移方程:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])。
dp[i][j]表示裝到第i個物品時揹包的最大價值,dp[i-1][j]可以理解為我們不裝i物品,此時揹包中的最大價值就是裝到第i-1個物品時揹包的最大價值;dp[i-1][j-w[i]]+v[i]可以理解為我們裝了i物品
二維陣列:
for(int i=1;i<=N;i++) { for(int j=0;j<=V;j++) { if(j<w[i])//第i件物品太重,放不進去 dp[i][j]=dp[i-1][j]; else dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]); } }
對於上面的狀態轉移方程我們無法再進行時間優化,但可以進行空間優化。
可以發現這樣的問題:
①二維陣列的遍歷順序為從第一行開始一行一行遍歷,且遍歷到第i行時不會用到第i-2行的資料,那麼i-2行及以前的資料都i沒有用了,我們可以將其清除。
②遍歷每一行時候只用到當前容量j和j-w[i]的資料,也就是第 i 次遍歷只需要 第 i-1 次遍歷中容量小於等於 j 的資料。
所以我們可以將利用滾動陣列優化空間。
一維陣列:
for(int i=1;i<=N;i++) { for(int j=V;j>=0;j++) { if(j<w[i])//第i件物品太重,放不進去 dp[j]=dp[j];else dp[j]=max(dp[j],dp[j-w[i]]+v[i]); } }
j從揹包容量為V開始遍歷,這樣可以保證dp[i][j]和dp[i][j-w[i]]中儲存的都是第i-1行的資料。
有個問題:j<w[i]時,dp[i]=dp[i]是無用的,所以此時可以什麼都不做,只需要遍歷到j>=w[i]。即:
for(int i=1;i<=N;i++) { for(int j=V;j>=0;j++) dp[j]=max(dp[j],dp[j-w[i]]+v[i]); }