1. 程式人生 > 遊戲資訊 >弈星面板延期上線,60點券給艾琳,五款新面板月中上線

弈星面板延期上線,60點券給艾琳,五款新面板月中上線

服了,揹包問題我真的是學了就忘學了就忘學了就忘……

寫個部落格總結一下,加深加深印象(供以後忘了的時候參考)


問題描述:

有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物品

,既然裝了i物品,那就應該從總容量中減去第i個物品的體積w[i],此時揹包剩餘容量為j-w[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]);
}