01背包问题 与 完全背包

本文详细解析了两种经典的背包问题——01背包与完全背包,并通过示例代码展示了如何使用动态规划解决这些问题,帮助读者理解并掌握这两种背包问题的核心算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、01背包

事例:

有N件物品和一个容量为V的背包。第i件物品所占用容量是v[i],价值是w[i]。求将哪些物品装入背包可使总价值最大。

思路:

  1. 要使装入背包内的物品价值最大,应优先装入占地空间小且价值大的物品。
  2. 我们不妨先找出容积从0到V 的各个容量所装物品的最优解。(就是指 当背包容量为1时装物品的最优解,当背包容量为2时装物品的最优解······一直到容积为N时装物品的最优解)。
  3. 那么如何求在容积为 v 时的最优解呢。那么就是把每种情况都放一下找出最优的。此时要用到的公式是f[j]=max(f[j],f[j-weight[i]]+value[i]);
  4. 下面来讲解一下该公式的含义

    f[j] 含义是当背包容量为 j 时的价值最优解(即怎样放物品能使背包总价值最大)。

    f[j-weight[i]] 含义是在放入第i件物品前背包价值的最优解。

    那么f[j-weight[i]]+value[i] 的含义就很简单了,即放入第i件物品时背包的价值。

    max(f[j],f[j-weight[i]]+value[i]) 就是比较原本背包容量为 j 时的最大价值与现在放第i件物品时背包价值,取最大值成为新的“背包容量为j时的最优解”(我们可以评出的看到背包的容量一直 j,没有改变)。

代码:

#include <iostream>
#include <cstring>
using namespace std;

const int N=4; //一共有N件物品。
const int V=5; //背包容量为V。
int weight[N]={1,2,2,3}; //各个物品的体积。
int value[N]={25,10,20,30};//各个物品的价值。
int f[V+1]; //f[j]意味容积j时的最优解。
int zeroonepack()
{
    int i,j;
    memset(f,0,sizeof(f)); //先把f[]初始化为0。
    for(i=0;i<N;i++)   //找出容积为 j 时向背包里装物品的最优解
    {
        for(j=V;j>=weight[i];j--)  
        {
            f[j]=max(f[j],f[j-weight[i]]+value[i]); 
            cout << j << " " << f[i] << endl;
        }
    }                 //求最优解结束
    return f[V]; //输出容积为V时的最佳解(即背包装满时的最优解)
}
int main()
{
    cout << zeroonepack() << endl; //调用函数
    return 0;
}

注意:

有的题目要求“恰好装满背包”时的最优解,有的题目则并没有要求必须把背包装满。
如果是第一种问法,要求恰好装满背包,那么在初始化时除了f[0]为0,其它f[1..V ]均设为−∞,这样就可以保证最终得到的f[V ]是一种恰好装满背包的最优解。

二、完全背包

事例:

有N种物品和一个容量为V 的背包,每种物品都可装入无限次。第i种物品所占容量为v[i],价值是W[i]。求将哪些物品装入背包可使总价值最大。

思路:

  1. 可将该问题看成01背包问题。
  2. 不同点是:
    01背包是一件物品只能用一次,于是我们从体积为V开始,倒着减。
    完全背包是从第1件物品开始,只要体积不超过背包容量V就可以一直装,那么一件物品就可以用好多次。

代码:

#include <iostream>
#include <cstring>
using namespace std;
const int N=4;
const int V=5;
int weight[N]={1,2,2,3};
int value[V]={25,10,20,30};
int f[V+1];
int completepace()
{
    memset(f,0,sizeof(f));
    int i,j;
    for(i=0;i<=N;i++)
    {
        for(j=weight[i];j<=V;j++)    //从第i件物品开始放
        {
            f[j]=max(f[j],f[j-weight[i]]+value[i]);
            cout << j << " " << f[j] << endl;
        }
        return f[V];
    }
}

int main()
{
    cout << completepace() << endl;
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值