【动态规划】01背包问题

文章介绍了背包问题,特别是01背包问题,这是一种在限定容量的背包中选择物品以最大化总权重的优化问题。通过动态规划的方法,定义状态表示为f(i,j),表示前i个物品中选取总体积不超过j时的最大权重。使用二维数组实现朴素的状态转移方程,并通过滚动数组优化成一维,减少空间复杂度。最后给出了一段ACwingluck例题的代码实现。
摘要由CSDN通过智能技术生成

背包问题

  1. 什么是背包问题呢,就是有n个物品,然后每个物品都有它的体积与权重,然后现在有一个体积为v的袋子,要求在这n个物品当中去选择一些物品放到袋子里面,确保不超出袋子的容量并且选择的物品权重和最大。

动态规划框架思路

  1. 对于动态规划问题主要分为两部分,状态表示与状态计算。
  2. 状态表示又分为两个方面,一方面是集合,一个集合就代表一种状态,在每一种状态里面有多个满足该状态的方案。然后对于这些方案都有一个结果值,这些结果值的最大值或最小值等就是状态表示的第二方面属性。
  3. 然后对于状态计算而言,其实就是集合的划分,并且求出状态转移方程,然后再代码实现,在代码实现的过程当中注意一下“定义域”。然后对于dp问题的话还可以进行优化,优化一般就是对代码或者状态转移方程进行等价变形。
  4. 在这里插入图片描述

01背包问题

  1. 01背包问题就是在背包问题的基础之上规定,对于n个物品,每一种物品它只能选零次或一次。
  2. 首先先去定义一个集合,也就是进行状态表示,f(i, j)。这个二维的集合表示:在前i个物品当中去选择,并且总体积小于等于j,然后集合的值也就是属性就是在满足这个状态的所有选法当中权重和最大的那个值。
    在这里插入图片描述
  3. 然后接下来就去进行状态计算,其实也就是集合的划分。集合划分的依据就是第i个物品到底选不选择,如下:当集合划分完成之后,就可以得到一个状态转移方程。
    在这里插入图片描述
  4. 有了这个状态转移方程之后,因为有i和j两个未知数,i的范围是从1到n,然后j的范围是从0到m,因此就可以代码实现朴素版的写法,具体在代码实现的过程当中需要去判断一下“定义域”的问题,这个去状态转移方程当中去注意一下就可以。
for (int i=1;i<=n;i++)
{
    for (int j=0;j<=m;j++)
    {
        f[i][j]=f[i-1][j];
        if (j-v[i]>=0)
        {
            f[i][j]=MAX(f[i][j],f[i-1][j-v[i]]+w[i]);
        }
    }
}
printf("%d\n",f[n][m]);
  1. 这个是朴素版的写法,然后接下来需要进行优化到一维。如果观察一下状态转移方程的话,如果说我要计算第i层的话,我只要有i-1层,上面的层我就不需要了。因此就可以用滚动数组来进行优化。并且我只需要与前面的上一层数据去进行比较,因此当我新的数据进来的时候,不能覆盖掉我等会儿还要去比较的上一层数据。所以说应该从右往左覆盖这个滚动数组。
    在这里插入图片描述
for (int i=1;i<=n;i++)
  {
      for (int j=m;j>=v[i];j--)
      {
          f[j]=MAX(f[j],f[j-v[i]]+w[i]);
      }
  }
  printf("%d\n",f[m]);

例题

来源:AcWing
luck
在这里插入图片描述

#include <stdio.h>
#define N 1010
#define MAX(a,b) ((a)>(b)?(a):(b))
int n,m;
int v[N];
int w[N];
int f[N];
int main()
{
    scanf("%d %d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%d %d",&v[i],&w[i]);
    }
    for (int i=1;i<=n;i++)
    {
        for (int j=m;j>=v[i];j--)
        {
            f[j]=MAX(f[j],f[j-v[i]]+w[i]);
        }
    }
    printf("%d\n",f[m]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

絕知此事要躬行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值