1. 程式人生 > >01揹包、完全揹包、多重揹包、分組揹包

01揹包、完全揹包、多重揹包、分組揹包

參考連結:

各種揹包的描述:

01揹包(ZeroOnePack): 有N件物品和一個容量為V的揹包。(每種物品均只有一件)第i件物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。

完全揹包(CompletePack): 有N種物品和一個容量為V的揹包,每種物品都有無限件可用。第i種物品的費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

多重揹包(MultiplePack): 有N種物品和一個容量為V的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

分組揹包有N件物品和一個容量為V的揹包。第i件物品的費用是c[i],價值是w[i]。這些物品被劃分為若干組,每組中的物品互相沖突,最多選一件。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

01揹包問題

容量為10的揹包,有5種物品,每種物品只有一個,其重量分別為5,4,3,2,1,其價值分別為1,2,3,4,5。 
設計演算法,實現揹包內物品價值最大。 
程式碼如下(輸出14)

#include <iostream>
#include<algorithm>

using namespace std;

int main() 
{
    int total_weight = 10;
    int w[6] = { 0,5,4,3,2,1};
    int v[6] = { 0,1,2,3,4,5};
    int dp[11] = { 0 };

    for (int i = 1; i <= 5; i++)
        for (int j = 10; j >= w[i]; j--)
            dp[j] = max(dp[j], dp[j - w[i]] + v[i]);

    cout << "總的價值為: " << dp[10] << endl;
    return 0;
}

完全揹包問題

容量為10的揹包,有5種物品,每種物品數量無限,其重量分別為5,4,3,2,1,其價值分別為1,2,3,4,5。 
設計演算法,實現揹包內物品價值最大。 
程式碼如下(輸出50)

#include <iostream>
#include<algorithm>

using namespace std;

int main() 
{
    int total_weight = 10;
    int w[6] = { 0,5,4,3,2,1};
    int v[6] = { 0,1,2,3,4,5};
    int dp[11] = { 0 };

    for (int i = 1; i <= 5; i++)
        for (int j = w[i]; j <= 10;j++)
                dp[j] = max(dp[j],dp[j - w[i]] + v[i]);

    cout << "總的價值為: " << dp[10] << endl;
    return 0;
}

多重揹包問題

容量為10的揹包,有5種物品,每種物品數量分別為1,2,1,2,1,其重量分別為5,4,3,2,1,其價值分別為1,2,3,4,5。 
設計演算法,實現揹包內物品價值最大。 
程式碼如下(輸出16)

#include <iostream>
#include<algorithm>

using namespace std;

int main()
{
    int total_weight = 10;
    int w[6] = { 0,5,4,3,2,1 };
    int v[6] = { 0,1,2,3,4,5 };
    int cot[6] = { 0,1,2,1,2,1 };
    int dp[11] = { 0 };

    for (int i = 1; i <= 5; i++)
        for (int k = 1; k <= cot[i];k++)
            for (int j = 10; j >= w[i]; j--)
                dp[j] = max(dp[j], dp[j - w[i]] + v[i]);

    cout << "總的價值為: " << dp[10] << endl;
    return 0;
}

分組揹包問題

乍一看好像很難的樣子,其實仔細想想很簡單,這種問題完全可以用01揹包解決。 對於分組揹包,可以這樣想:雖然分成很多組,但只能選一個,或者不選,這和01揹包是一樣的,也就是說,對於01揹包裡每一個獨一無二的物品,對應的分組揹包就是每一組中選擇一個物品,這樣來看,完全就是01揹包問題。

下面是狀態方程:

for(int i = 1; i <= z; i++)
for(int j = V; j >= 1; j--)
for(int k = 1; k <= n; k++)
dp[j] = max(dp[j - w[i][k]] + p[i][k], dp[j]);


其中,z是分組數,V是揹包體積,n是每組物品數量,w和p分別是第i組第k個物品的體積和價值。

為什麼要這樣寫呢?可以想一下01揹包的狀態方程,和這個外兩層的迴圈是一樣的,不一樣的是裡面又加了一層,這層迴圈是遍歷每一組的物品用的,對於dp[]中每一個狀態都是迴圈了一遍每一組的物品才換到下一個的,所以對後面的沒有影響,也就保證了每組物品最多隻有一件。