01背包笔记 模拟+推导全过程

贪心可行吗?

关于这个问题 各位同学可以思考一下!

如果用贪心的思想每次选取最大的放入背包

那么可以试试以下这个数据

物品编号        体积        价值
15600
22250
33450

若背包容量为5

那么我们第一次选取最大的物品1,获得的价值为600 此时背包已经装满

但是此时是否为装满背包获取的最大价值呢?

答案是否定的!!!

因为我们选取物品2+物品3 体积占用为5 价值为250+450=700 

显然是比第一种情况是价值更大

因此这类问题我们不可以用贪心来思考

于是便引入了我们今天的模型01背包

模拟大法

因为贪心的思想是行不通的,所以我们可以进行模拟所有情况看一下能不能寻找出什么规律

这里第一行是一个物品都不选的情况那么无论分配多少体积 他的价值都为0

第二行选取物品1,当体积为5的时候,而体积0-4因为无法装满所以价值为0

(这里为何要讨论0-4这种情况呢,那是因为我们实际的数据是不确定的,我们讨论要遵循不重不漏的原则,虽然这里显得多余,但是有的数据就需要这种讨论,比如如果有一个物品体积为1价值为200 那么在体积为1的时候他就可以被装入)

再来看物品2,物品2的体积为2,因此当体积为2的时候才可以装入,价值为250,后面2-4一致

然而当背包的体积为5的时候,情况就发生了改变

此时我们需要讨论两种情况

1 不选物品2 那么我们就选取物品1 价值为600

2 选取物品2 那么物品1就没法选了,因为物品2需要占用体积2 剩余体积只有3 物品1无法放入背包 此时价值为250

对1和2选取一个最大的情况 因此当需要在前两个物品中进行选择的时候我们选取物品1放入背包,获取的最大价值为600

然后我们看从前3个物品中进行选择

当背包体积为0-1时候,任何物品都没法放入背包 背包价值为0

当背包体积为2的时候,我们可以选择物品2 这时背包价值为250

当背包体积为3的时候    我们面临两种选择

1 不选第3个物品 从前两个物品中进行选择,那么我们的最大价值就是上一行的价值从前两个物品中选,价值最大为250

2选取第3个物品 先给第三个物品预留空间 ,此时背包3-3=0没有多余空间,那么只能放物品3 最大价值为450

背包体积为4时同理

当背包体积为5时,我们有两种选法

1不选第3个物品 即从前两个物品中选择 背包体积为5的时候的最大价值

2选第3个物品 那么先给第三个物品预留空间,那么还剩下两个空间,再从前两个中选择,体积不超过2,由上行数据我们可以看出,最大价值为250,250+450=700 从而得出最大价值

也就得出了从3个物品中选,体积为5时的最大价值

递推公式

我们可以发现上面

每个物品 只有选和不选两种情况  

选第i个物品:就是先预留空间j-v dp[i-1][j-v]就表示前i-1个物品中选体积不超过j-v的最大价值 然后再加上物品i的价值

不选物品i:就是直接从前i-1个物品中选体积不超过j 

而我们要求就是再背包体积为j的情况下能获得的最大值

我们可以设置一个二维数组dp[n][m]

dp[i][j]表示从前i个物品中选,体积不超过j的最大价值

根据上述我们可以得出  dp[i][j]=max(dp[i-1][j],dp[i-1][j-v]+w)

因为每次更新都只有选和不选两种情况

关于初始化的问题

我们物品编号从1开始 所以当dp[0][j]表示一个物品都不选体积为j时的最大价值  都一个物品没选了 那价值肯定为0 这是第0行的数据 所以默认为0 

然后就是dp[i][0]表示前i个物品中选 背包体积为0时的最大价值 背包体积为0 一个都装不下 所以dp[i][0]也都是0

然后我们下面的代码读入i和j都是从1开始读入 又因为我们dp[i][j]开在全局变量默认为0 所以此时不用初始化 或者说已经初始化完毕

代码

#include <iostream>
using namespace std;
int v[1010],w[1010];
int f[1010][1010];//这里开成全局变量 所以默认为0 f[0][0-m]表示一个物品都不选 总体积不超过0-m 因为一个都没选所以默认为0
//
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];//读入物品的体积和价值
    
    //从1开始 不用初始化 
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            {
                if(v[i]>j)f[i][j]=f[i-1][j];//如果当前物品比体积还要大 那么就不选该物品 //选的时候可能不存在
                //此时等同于从前i-1中选体积不超过j
                else
                f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
                //否则就是选与不选两者取最大值
            }
    }
    cout<<f[n][m];
    return 0;
}

  • 25
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值