01背包问题

首先背包问题,属于动态规划问题,动态规划问题我们主要是找出动态转移方程!

我们用一道例题讲解:
让我假设现在的背包的容量是 C=10

物品编号:1 2 3
物品重量:5 6 4
物品价值:20 10 12

用v[i]表示物品价值,w[i]表示物品重量,要使得放入背包的物品价值最大化,我们知道用贪心是不行的!
动态转移方程:dp[i][j]=max( (dp[i-1][ j−w[i] ] ) + v[i] , dp[i-1][j])

定义状态dp[i][j],我解释一下这个数组
我们暂时可以理解为,我可以放入前i个物品,我背包可承受总重量为j。
(注意可以放入前i个物品,不代表前i个物品都放入了!)
那么dp[i][j]表示当前这个包(解锁了第i件物品,重量承载量为j)的总价值!

我们模拟一下:

当i=1,j<5,证明我可以放入第1件物品,代表第一件物品,我解锁了,可以拿走,只要我当前可承载重量j>w[1]即可装入包中!那么我们发现w[1]=5,当j<5时,我背包承受不住,所以放不下第一件物品,所以j<5时 da[i][j]=0;
当j>5时,我们可以装下第一件物品,要注意我只解锁了i=1第一件,没解锁其他件物品,所以当j>5时,dp[1][j]=20;

我们再接再厉,模拟i=2的情况!

当i=2时,我们的背包解锁了第二件物品,证明我的包既可以装下第一件物品,也可以装下第二件物品,只要我的承载量j够,就可以都带走,不然我们要选择价值最大的装进去!
我们可以看到第二件物品的重量w[2]=6,所以当j<6时,我们的包无法承载第二件,所以j<6,我们只能拿第一件物品,所以j<6时,dp[2][j]=20;

当j>6时,我们回顾一下动态转移方程:dp[i][j]=max( (dp[i-1][ j−w[i] ] ) + v[i] , dp[i-1][j]),j>6我们可以从第一件和第二件选一件拿,但是无法都带走,我们怎么从代码实现呢,就是动态转移方程的逻辑,我们可以从现在时,和过去时来理解这个方程
左边的dp[i][j],代表我目前的背包,已经解锁了i件物品,可承载的重量为j,max函数中第一个dp[i-1][j-w[i]],代表过去的背包,只解锁了第i-1件物品但是只装了j-w[i]的重量的物品,

我在这里多说一句,无论实际有没有物品装在背包里,我们都当已经装了重量为j的物品对待,承重量为 j-w[i]的包里可能一件物品也没有装,但是我们默认装了j-w[i],这样方便理解!

然后我在加上当前第i件物品的v[i]即dp[i-1][j-w[i]]+v[i],就是目前我装下了第i件物品的总价值,max函数第二个dp[i-1][j],代表过去同样装了重量为j的物品,但是只解锁了i-1件物品产生的总价值,我们进行比较选出最大价值的!
举个例子,dp[2][9]=max(dp[1][9-6]+v[2],dp[1][9])我们可以算出
(dp[1][3]+10=0+10=10)<dp[1][9]=20所以我们dp[2][9]=dp[1][9]=20;
所以我们很容易得出当i=2时,只要j>5dp[2][j]=20,j<5dp[2][j]=0

最终的背包一定是最优解答即d[m][v]

我给大家拉一个表格,把每一种情况都写下来给大家!
每一个窗格,代表dp[i][j],所以的dp[i][j]都依赖于它的上一行!
在这里插入图片描述

代码:

#include <iostream>

using namespace std;
int w[105],v[105];
int dp[105][1005];
int main()
{

    int t,m,res;
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&w[i],&v[i]);
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=t;j>=0;j--)
        {
            if(j>=w[i])//只有当j>当前w[i]它才有选择的权力
            {
                dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]);
            }else{
              dp[i][j]=dp[i-1][j];
            }
        }
    }
    printf("%d",dp[m][t]);

    return 0;
}

下面是01背包的优化以及,完全背包大家可以学习一下!
01背包二维到一维优化

完全背包
谢谢观看,多多点赞支持!

  • 32
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值