01背包、彻底背包、多重背包、分组背包

参考连接:ios

01背包、彻底背包、多重背包问题的C++实现 算法

史上最易懂的01背包,彻底背包,多重背包讲解spa

浅谈分组背包.net

 

各类背包的描述:设计

01背包(ZeroOnePack): 有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可以使价值总和最大。code

彻底背包(CompletePack): 有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可以使这些物品的费用总和不超过背包容量,且价值总和最大。blog

多重背包(MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可以使这些物品的费用总和不超过背包容量,且价值总和最大。ip

分组背包有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。这些物品被划分为若干组,每组中的物品互相冲突,最多选一件。求解将哪些物品装入背包可以使这些物品的费用总和不超过背包容量,且价值总和最大。get

 

01背包问题

容量为10的背包,有5种物品,每种物品只有一个,其重量分别为5,4,3,2,1,其价值分别为1,2,3,4,5。 
设计算法,实现背包内物品价值最大。 
代码以下(输出14)it

#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[]中每个状态都是循环了一遍每一组的物品才换到下一个的,因此对后面的没有影响,也就保证了每组物品最多只有一件。